Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copilot PR Review Instructions — FastEdge-sdk-rust

## Constitution

This repository is `fastedge` (crate) — the Rust SDK for Gcore FastEdge. It provides the `#[fastedge::http]` and `#[wstd::http_server]` handler macros, type conversions, an outbound HTTP client, and ProxyWasm FFI wrappers for CDN apps.

### Principles (enforce during review)

1. **Handler preference** — `#[wstd::http_server]` (async, wasm32-wasip2) is the recommended handler for new HTTP apps. `#[fastedge::http]` is legacy. New examples must use `wstd`.
2. **No over-engineering** — Simple solutions over complex abstractions. Three similar lines > premature abstraction.
3. **Platform constraints** — Only stdout is captured; `eprintln!` output is silently lost. Flag any use of stderr in code or examples.
4. **CDN/HTTP separation** — CDN apps (proxy-wasm filters) and HTTP apps (standalone handlers) are independent application types with different architectures and lifecycles. Never mix their APIs.
5. **WIT submodule integrity** — `wit/` files come from `G-Core/FastEdge-wit` submodule. Never modify them directly.

### Public API contract

The public API surface is defined by:
- `src/lib.rs` — Core types (`Body`, `Error`), type conversions, `send_request`
- `derive/src/lib.rs` — `#[fastedge::http]` proc macro
- `src/proxywasm/` — ProxyWasm FFI wrappers (KV store, secrets, dictionary, utils)
- `src/http_client.rs` — Outbound HTTP client

Changes to these surfaces require updated `docs/`, updated tests, and a semver-appropriate version bump.

## Generated Content — `docs/`

Files in `docs/` are **machine-generated** from source code by `./fastedge-plugin-source/generate-docs.sh`. They must not be edited by hand — manual changes will be silently overwritten on the next generation run.

### When reviewing PRs that touch `docs/`:

- **Never** suggest manual edits to any file in `docs/`
- If docs are stale or incorrect, suggest: **Run `./fastedge-plugin-source/generate-docs.sh`**
- If the generated output itself is wrong (e.g., wrong structure, missing section), the fix belongs in `fastedge-plugin-source/.generation-config.md`, not in `docs/` directly
- If a PR modifies `docs/` files without a corresponding source code change, flag it — the change should come from the generation script, not a hand-edit

### When reviewing PRs that change source code covered by `docs/`:

- Check whether the change affects the public API or user-facing behavior
- If yes, and `docs/` was not regenerated in the same PR, **request changes** with:
> Source code affecting public API was changed but docs/ was not regenerated.
> Run: `./fastedge-plugin-source/generate-docs.sh`

## Documentation Freshness

### Public API changes (must regenerate docs/)
- New, modified, or removed public types/functions in `src/lib.rs`
- Changes to `#[fastedge::http]` macro behavior in `derive/src/lib.rs`
- Changes to ProxyWasm wrapper APIs in `src/proxywasm/`
- Changes to outbound HTTP client in `src/http_client.rs`
- New or modified WIT interfaces in `wit/`
- Changes to `Cargo.toml` (version, features, dependencies)

### Mapping: code location → doc file

| Code path | Doc file |
| --------------------------------------------- | --------------------- |
| `src/lib.rs` (Body, Error, send_request) | `docs/SDK_API.md` |
| `derive/src/lib.rs` (handler macros) | `docs/SDK_API.md` |
| `src/http_client.rs` (outbound HTTP) | `docs/SDK_API.md` |
| `src/proxywasm/key_value.rs` | `docs/HOST_SERVICES.md` |
| `src/proxywasm/secret.rs` | `docs/HOST_SERVICES.md` |
| `src/proxywasm/dictionary.rs` | `docs/HOST_SERVICES.md` |
| `src/proxywasm/utils.rs` | `docs/HOST_SERVICES.md` |
| `src/proxywasm/` (CDN lifecycle, FFI) | `docs/CDN_APPS.md` |
| `Cargo.toml` (version, features) | `docs/INDEX.md` |
| `fastedge-plugin-source/manifest.json` | `.github/copilot-instructions.md` |

### Violation example

> PR changes `send_request` signature in `src/lib.rs` but `docs/SDK_API.md` still shows the old signature → **request changes**. Run `./fastedge-plugin-source/generate-docs.sh` before merge.

### Quickstart protection

If any public API signature or behavior changes, check whether `docs/quickstart.md` examples are still accurate. Request regeneration if examples would no longer work against the updated code.

## Pipeline source contract

If `fastedge-plugin-source/manifest.json` lists source files that overlap with files changed in this PR, request that `docs/` is regenerated (run `./fastedge-plugin-source/generate-docs.sh`) to keep the plugin pipeline's source material current.

## Quality Rules

- All public function signatures in docs must match actual source declarations
- No `eprintln!` or `eprint!` in any code or examples — output is lost on the platform
- New HTTP examples must use `#[wstd::http_server]`, not `#[fastedge::http]`
- No marketing language in documentation — precise, technical prose only
22 changes: 22 additions & 0 deletions .github/workflows/copilot-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Copilot Instructions Sync

on:
pull_request:
paths:
- fastedge-plugin-source/manifest.json
- fastedge-plugin-source/check-copilot-sync.sh
- .github/copilot-instructions.md
- .github/workflows/copilot-sync.yml
- examples/**
- docs/**

jobs:
check-sync:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v5

- name: Check manifest ↔ copilot-instructions sync
run: bash fastedge-plugin-source/check-copilot-sync.sh

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Comment on lines +15 to +22
6 changes: 5 additions & 1 deletion examples/cdn/ab_testing/fixtures/existing-cookie-a.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/ab_testing/fixtures/existing-cookie-b.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/ab_testing/fixtures/missing-config.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@
"request.host": "example.com",
"request.path": "/landing"
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/ab_testing/fixtures/new-visitor.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
26 changes: 11 additions & 15 deletions examples/cdn/ab_testing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,11 @@ impl RootContext for AbTestingRoot {
}

fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
Some(Box::new(AbTestingContext {
variant: String::new(),
experiment_name: String::new(),
}))
Some(Box::new(AbTestingContext))
}
}

struct AbTestingContext {
variant: String,
experiment_name: String,
}
struct AbTestingContext;

impl Context for AbTestingContext {}

Expand Down Expand Up @@ -94,9 +88,6 @@ impl HttpContext for AbTestingContext {
assigned = if now % 2 == 0 { "A" } else { "B" }.to_string();
}

self.variant = assigned.clone();
self.experiment_name = experiment_name.clone();

// Rewrite request path
let path = self
.get_property(vec!["request.path"])
Expand Down Expand Up @@ -130,16 +121,21 @@ impl HttpContext for AbTestingContext {
}

fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action {
if self.variant.is_empty() {
// Recover the assigned variant and experiment name from the request headers set in
// on_http_request_headers. Instance state does not survive the nginx -> core-proxy hop.
let Some(variant) = self.get_http_request_header("X-Variant") else {
return Action::Continue;
}
};
let Some(experiment_name) = self.get_http_request_header("X-Experiment") else {
return Action::Continue;
};

let cookie = format!(
"fe_exp_{}={}; Path=/; Max-Age=86400; SameSite=Lax",
self.experiment_name, self.variant
experiment_name, variant
);
self.add_http_response_header("Set-Cookie", &cookie);
self.add_http_response_header("X-Variant", &self.variant);
self.add_http_response_header("X-Variant", &variant);

Action::Continue
}
Expand Down
6 changes: 5 additions & 1 deletion examples/cdn/api_key/fixtures/happy-path.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/api_key/fixtures/invalid-key.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/api_key/fixtures/missing-header.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/api_key/fixtures/missing-secret.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@
},
"body": ""
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
4 changes: 4 additions & 0 deletions examples/cdn/body/fixtures/client.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@
"x-debugger-content": "body-only"
},
"body": "Hello Client, this is a test message"
},
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
4 changes: 4 additions & 0 deletions examples/cdn/body/fixtures/skip.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@
"x-debugger-content": "body-only"
},
"body": "Hello World, this is a test message"
},
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cache_control/fixtures/error-status.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cache_control/fixtures/happy-path.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cache_control/fixtures/json-api.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cache_control/fixtures/static-asset.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cache_control/fixtures/xml-api.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cors/fixtures/disallowed-origin.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cors/fixtures/happy-path.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cors/fixtures/no-origin.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
6 changes: 5 additions & 1 deletion examples/cdn/cors/fixtures/preflight.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@
"enabled": true,
"path": "."
},
"logLevel": 2
"logLevel": 2,
"wasm": {
"path": "<workspace>/.fastedge-debug/app.wasm",
"description": "Default debugger WASM binary"
}
}
Loading
Loading