From 067df66bcef0fa638b3e02b33a21ab445f939a0b Mon Sep 17 00:00:00 2001 From: Paul Osborne Date: Thu, 4 Jun 2026 17:57:55 -0500 Subject: [PATCH 1/2] Initial Default Python Starter Kit This basic examples includes the key pieces (pyproject.toml, fastly.toml, etc.) setup to use the fastly SDK. It makes use of the flask microframework based on the SDKs support for WSGI. --- .fastlyignore | 5 +++ .github/CODEOWNERS | 1 + .github/dependabot.yml | 11 ++++++ .github/workflows/test.yml | 44 ++++++++++++++++++++++++ .gitignore | 16 +++++++++ LICENSE | 21 ++++++++++++ PLACEHOLDER.md | 2 -- README.md | 30 +++++++++++++++++ SECURITY.md | 9 +++++ fastly.toml | 11 ++++++ main.py | 69 ++++++++++++++++++++++++++++++++++++++ pyproject.toml | 12 +++++++ welcome-to-compute.html | 30 +++++++++++++++++ 13 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 .fastlyignore create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 LICENSE delete mode 100644 PLACEHOLDER.md create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 fastly.toml create mode 100644 main.py create mode 100644 pyproject.toml create mode 100644 welcome-to-compute.html 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..6bff3aa --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 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..c93ad8a --- /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 lightweight framework that implement 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 as well. + +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..4222d08 --- /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://developer.fastly.com/learning/compute/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 pre-configured 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 pre-configured 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 + + + + + + From 70831d6ac56adb4c4ddd6be4f0a699713947fc6b Mon Sep 17 00:00:00 2001 From: Paul Osborne Date: Tue, 16 Jun 2026 18:18:07 -0500 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Kevin P. Fleming --- LICENSE | 2 +- README.md | 6 +++--- main.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/LICENSE b/LICENSE index 6bff3aa..7b9803a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Fastly +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 diff --git a/README.md b/README.md index c93ad8a..3cb54fb 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,13 @@ Get to know the Fastly Compute environment with a basic starter that demonstrate ## 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 +- 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 lightweight framework that implement 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 as well. +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. diff --git a/main.py b/main.py index 4222d08..88e70f7 100644 --- a/main.py +++ b/main.py @@ -22,12 +22,12 @@ def log_service_version(): @app.route("/", methods=["GET"]) def index(): # Below are some common patterns for Compute services using Python. - # Head to https://developer.fastly.com/learning/compute/python/ to discover more. + # 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 pre-configured backends (by specifying `fastly_backend`). + # or static backends (by specifying `fastly_backend`). # # Example: # from fastly_compute import requests @@ -35,7 +35,7 @@ def index(): # # Using dynamic backends: # resp = requests.get("https://http-me.fastly.dev/get") # - # # Using a pre-configured static backend named "example-backend": + # # Using a static backend named "example-backend": # resp = requests.get( # "https://example.com/api/data", # headers={"X-Custom-Header": "Welcome!"}, @@ -64,6 +64,6 @@ def index(): return welcome_page, 200, {"Content-Type": "text/html; charset=utf-8"} -# Create the HTTP handler using WSGI; this adapts the fastly compute +# 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)