diff --git a/.fastlyignore b/.fastlyignore new file mode 100644 index 0000000..c6a308c --- /dev/null +++ b/.fastlyignore @@ -0,0 +1,5 @@ +__pycache__/ +.venv/ +.ruff_cache/ +/bin +/pkg diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..da153aa --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @fastly/developer-relations diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..288074f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..6e5c254 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,44 @@ +name: Test + +on: + pull_request: + +defaults: + run: + shell: bash + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository contents + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + + - name: Format + run: uvx ruff format --check . + + - name: Lint + run: uvx ruff check . + + - name: Install Fastly CLI + uses: fastly/compute-actions/setup@v13 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build (using CLI) + uses: fastly/compute-actions/build@v13 + + - name: Upload WASM package as an artifact + uses: actions/upload-artifact@v7 + with: + name: wasm-package + path: bin/main.wasm + if-no-files-found: error + compression-level: 0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68b95c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Environments +.venv/ +env/ +venv/ + +# Ruff/linters cache +.ruff_cache/ + +# Fastly Compute build artifacts +/bin/ +/pkg/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7b9803a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Fastly + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/PLACEHOLDER.md b/PLACEHOLDER.md deleted file mode 100644 index 96ee30d..0000000 --- a/PLACEHOLDER.md +++ /dev/null @@ -1,2 +0,0 @@ -# Placeholder for Review - diff --git a/README.md b/README.md new file mode 100644 index 0000000..3cb54fb --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# Default Starter Kit for Python + +[![Deploy to Fastly](https://deploy.edgecompute.app/button)](https://deploy.edgecompute.app/deploy) + +Get to know the Fastly Compute environment with a basic starter that demonstrates routing, simple synthetic responses and code comments that cover common patterns. + +**For more details about this and other starter kits for Compute, see the [Fastly Documentation Hub](https://www.fastly.com/documentation/solutions/starters/)**. + +## Features + +- Shows use of [WSGI][wsgi] to handle requests +- Shows dependency management with [`uv`][uv] via `pyproject.toml` +- Uses [Flask][flask] from [PyPI][pypi] for basic request routing and handling +- Build synthetic responses at the edge + +## Understanding the code + +This starter kit is intentionally fairly minimal; while Flask is included as a dependency alongside the [Fastly Compute SDK for Python][compute-sdk-python], this is meant primarily as a demonstration of use of a lightweight framework that implements the [WSGI][wsgi] interface. [Bottle][bottle] is another popular microframework which may be used. Python services may also be written without any additional framework dependencies. + +The starter doesn't require the use of any backends. Once deployed, you will have a Fastly service running on Compute that can generate synthetic responses at the edge. + +## Security issues + +Please see [SECURITY.md](SECURITY.md) for guidance on reporting security-related issues. + +[wsgi]: https://peps.python.org/pep-3333/ +[bottle]: https://bottlepy.org/docs/dev/ +[uv]: https://docs.astral.sh/uv/ +[pypi]: https://pypi.org/ +[flask]: https://flask.palletsprojects.com/en/stable/ diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..f2aa82e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +## Report a security issue + +The project team welcomes security reports and is committed to providing prompt attention to security issues. Security issues should be reported privately via [Fastly’s security issue reporting process](https://www.fastly.com/security/report-security-issue). + +## Security advisories + +Remediation of security vulnerabilities is prioritized by the project team. The project team endeavors to coordinate remediation with third-party stakeholders, and is committed to transparency in the disclosure process. The team announces security issues via the [Fastly Developer Hub Starter Kits](https://developer.fastly.com/solutions/starters/) site on a best-effort basis. + +Note that communications related to security issues in Fastly-maintained OSS as described here are distinct from [Fastly Security Advisories](https://www.fastly.com/security-advisories). diff --git a/fastly.toml b/fastly.toml new file mode 100644 index 0000000..22ce64e --- /dev/null +++ b/fastly.toml @@ -0,0 +1,11 @@ +# This file describes a Fastly Compute package. To learn more visit: +# https://www.fastly.com/documentation/reference/compute/fastly-toml + +authors = [] +description = "A basic starter kit that demonstrates routing and simple responses in Python." +language = "python" +manifest_version = 3 +name = "fastly-compute-python-app" + +[scripts] +build = "uv run fastly-compute-py build" diff --git a/main.py b/main.py new file mode 100644 index 0000000..88e70f7 --- /dev/null +++ b/main.py @@ -0,0 +1,69 @@ +import os +import pathlib +from flask import Flask +from fastly_compute.wsgi import WsgiHttpIncoming + +app = Flask(__name__) + +# Module-level functionality executes at build-time as part of +# memory snapshotting; the filesystem is not available at runtime; instead +# execution of the code resumes from this snapshot when an incoming +# request is received, greatly reducing startup costs. +welcome_page_path = pathlib.Path(__file__).parent / "welcome-to-compute.html" +welcome_page = welcome_page_path.read_text(encoding="utf-8") + + +@app.before_request +def log_service_version(): + # Log service version + print(f"FASTLY_SERVICE_VERSION: {os.environ.get('FASTLY_SERVICE_VERSION', '')}") + + +@app.route("/", methods=["GET"]) +def index(): + # Below are some common patterns for Compute services using Python. + # Head to https://www.fastly.com/documentation/guides/compute/developer-guides/python/ to discover more. + + # 1. Sending HTTP Requests (via requests facade) + # The Fastly SDK for Python provides a requests-compatible facade. + # Outgoing requests can use dynamic backends (by passing a full URL) + # or static backends (by specifying `fastly_backend`). + # + # Example: + # from fastly_compute import requests + # + # # Using dynamic backends: + # resp = requests.get("https://http-me.fastly.dev/get") + # + # # Using a static backend named "example-backend": + # resp = requests.get( + # "https://example.com/api/data", + # headers={"X-Custom-Header": "Welcome!"}, + # fastly_backend="example-backend" + # ) + + # 2. Real-Time Log Streaming (Logging) + # The SDK provides direct integration with Fastly's Real-Time Log Streaming endpoints, + # both via direct endpoint writing and standard Python library logging. + # + # Example 1: Direct endpoint logging + # from fastly_compute.log import LogEndpoint + # + # with LogEndpoint.open("my-log-endpoint") as endpoint: + # endpoint.write("Hello from the edge!") + # + # Example 2: Integration with Python standard library `logging` + # import logging + # from fastly_compute.log import FastlyLogHandler + # + # handler = FastlyLogHandler(default_endpoint="my-log-endpoint") + # logger = logging.getLogger("my-app") + # logger.addHandler(handler) + # logger.info("This is an info-level log message") + + return welcome_page, 200, {"Content-Type": "text/html; charset=utf-8"} + + +# Create the HTTP handler using WSGI; this adapts the Fastly Compute +# platform to the WSGI standard for use with a variety of frameworks. +HttpIncoming = WsgiHttpIncoming(app) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ab54305 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[project] +name = "fastly-compute-python-app" +version = "0.1.0" +description = "A basic starter kit for Python on Fastly Compute" +requires-python = ">=3.12" +dependencies = [ + "flask>=3.1.3", + "fastly-compute>=0.1.2", +] + +[tool.fastly-compute] +entry = "main" diff --git a/welcome-to-compute.html b/welcome-to-compute.html new file mode 100644 index 0000000..cc18336 --- /dev/null +++ b/welcome-to-compute.html @@ -0,0 +1,30 @@ + + + + + + + Welcome to Fastly Compute + + + + + +