@yiaany/ghostapi 0.1.9 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/CONTRIBUTING.md +132 -119
- package/LICENSE +21 -21
- package/PROVENANCE.md +13 -0
- package/README.md +78 -84
- package/SECURITY.md +56 -53
- package/dist/actions/gateway.js +320 -72
- package/dist/actions/gateway.js.map +1 -1
- package/dist/actions/index.d.ts +2 -2
- package/dist/actions/index.js +1 -1
- package/dist/actions/index.js.map +1 -1
- package/dist/agents/agentPrompt.js +7 -5
- package/dist/agents/agentPrompt.js.map +1 -1
- package/dist/ai/aiClient.js +5 -5
- package/dist/ai/aiClient.js.map +1 -1
- package/dist/ai/aiGenerator.js +66 -26
- package/dist/ai/aiGenerator.js.map +1 -1
- package/dist/ai/genericInference.js +151 -36
- package/dist/ai/genericInference.js.map +1 -1
- package/dist/ai/prompts.js +55 -49
- package/dist/ai/prompts.js.map +1 -1
- package/dist/approvals/approvalInbox.js +649 -133
- package/dist/approvals/approvalInbox.js.map +1 -1
- package/dist/approvals/index.d.ts +2 -2
- package/dist/approvals/index.js +1 -1
- package/dist/approvals/index.js.map +1 -1
- package/dist/behavior/behaviorStore.js +34 -14
- package/dist/behavior/behaviorStore.js.map +1 -1
- package/dist/cache/index.js +14 -5
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/index.js +226 -93
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/openUrl.js +17 -3
- package/dist/cli/openUrl.js.map +1 -1
- package/dist/cli/parser.js +79 -18
- package/dist/cli/parser.js.map +1 -1
- package/dist/config/dataPaths.js +4 -2
- package/dist/config/dataPaths.js.map +1 -1
- package/dist/config/localConfig.js +5 -2
- package/dist/config/localConfig.js.map +1 -1
- package/dist/config/serverConfig.js +11 -5
- package/dist/config/serverConfig.js.map +1 -1
- package/dist/contracts/contract.js +311 -83
- package/dist/contracts/contract.js.map +1 -1
- package/dist/contracts/index.d.ts +2 -2
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/credentials/credentialBroker.js +391 -79
- package/dist/credentials/credentialBroker.js.map +1 -1
- package/dist/credentials/index.d.ts +2 -2
- package/dist/credentials/index.js +1 -1
- package/dist/credentials/index.js.map +1 -1
- package/dist/dashboard/app.js +823 -685
- package/dist/dashboard/dashboard.js.map +1 -1
- package/dist/dashboard/index.html +704 -267
- package/dist/dashboard/styles.css +1040 -349
- package/dist/egress/capabilities.js +55 -25
- package/dist/egress/capabilities.js.map +1 -1
- package/dist/egress/linuxBootstrap.js +47 -11
- package/dist/egress/linuxBootstrap.js.map +1 -1
- package/dist/egress/run.js +170 -31
- package/dist/egress/run.js.map +1 -1
- package/dist/errors/errorEngine.js +15 -3
- package/dist/errors/errorEngine.js.map +1 -1
- package/dist/errors/providerErrors.js.map +1 -1
- package/dist/evals/evals.js +304 -78
- package/dist/evals/evals.js.map +1 -1
- package/dist/evals/index.d.ts +2 -2
- package/dist/evals/index.js +1 -1
- package/dist/evals/index.js.map +1 -1
- package/dist/evidence/index.d.ts +2 -2
- package/dist/evidence/index.js +1 -1
- package/dist/evidence/index.js.map +1 -1
- package/dist/evidence/report.d.ts +1 -1
- package/dist/evidence/report.js +263 -79
- package/dist/evidence/report.js.map +1 -1
- package/dist/fault/faultLab.js +24 -9
- package/dist/fault/faultLab.js.map +1 -1
- package/dist/index.d.ts +42 -42
- package/dist/index.js +21 -21
- package/dist/index.js.map +1 -1
- package/dist/inventory/analysis.d.ts +1 -1
- package/dist/inventory/analysis.js +174 -50
- package/dist/inventory/analysis.js.map +1 -1
- package/dist/inventory/index.d.ts +4 -4
- package/dist/inventory/index.js +3 -3
- package/dist/inventory/index.js.map +1 -1
- package/dist/inventory/inventoryController.js +362 -115
- package/dist/inventory/inventoryController.js.map +1 -1
- package/dist/inventory/types.js +680 -140
- package/dist/inventory/types.js.map +1 -1
- package/dist/ledger/actionLedger.js +355 -78
- package/dist/ledger/actionLedger.js.map +1 -1
- package/dist/ledger/index.d.ts +2 -2
- package/dist/ledger/index.js +1 -1
- package/dist/ledger/index.js.map +1 -1
- package/dist/mcp/server.js +26 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +1 -1
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/policy.js +112 -32
- package/dist/policy/policy.js.map +1 -1
- package/dist/productTelemetry/index.js +71 -20
- package/dist/productTelemetry/index.js.map +1 -1
- package/dist/providers/conformance.js +10 -5
- package/dist/providers/conformance.js.map +1 -1
- package/dist/providers/discord.js +2 -2
- package/dist/providers/generic.js +3 -3
- package/dist/providers/github.js +2 -2
- package/dist/providers/index.d.ts +3 -3
- package/dist/providers/index.js +2 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.js +3 -3
- package/dist/providers/packs/resendPack.js +51 -25
- package/dist/providers/packs/resendPack.js.map +1 -1
- package/dist/providers/packs/stripePack.js +590 -121
- package/dist/providers/packs/stripePack.js.map +1 -1
- package/dist/providers/registry.js +4 -4
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/runtime.js +7 -6
- package/dist/providers/runtime.js.map +1 -1
- package/dist/providers/stripeWebhook.js +39 -10
- package/dist/providers/stripeWebhook.js.map +1 -1
- package/dist/providers/twilio.js +2 -2
- package/dist/proxy/cacheKey.js +9 -2
- package/dist/proxy/cacheKey.js.map +1 -1
- package/dist/proxy/providerDetector.js +22 -9
- package/dist/proxy/providerDetector.js.map +1 -1
- package/dist/proxy/proxyHandler.js +57 -22
- package/dist/proxy/proxyHandler.js.map +1 -1
- package/dist/proxy/requestNormalizer.js +4 -2
- package/dist/proxy/requestNormalizer.js.map +1 -1
- package/dist/reliability/costGovernance.js +211 -49
- package/dist/reliability/costGovernance.js.map +1 -1
- package/dist/reliability/index.d.ts +8 -8
- package/dist/reliability/index.js +4 -4
- package/dist/reliability/index.js.map +1 -1
- package/dist/reliability/reconciliation.js +274 -65
- package/dist/reliability/reconciliation.js.map +1 -1
- package/dist/reliability/runtimeHealth.js +127 -35
- package/dist/reliability/runtimeHealth.js.map +1 -1
- package/dist/reliability/slo.js +257 -50
- package/dist/reliability/slo.js.map +1 -1
- package/dist/report/safetyReport.d.ts +6 -0
- package/dist/report/safetyReport.js +56 -12
- package/dist/report/safetyReport.js.map +1 -1
- package/dist/rules/aiRules.js +5 -5
- package/dist/rules/aiRules.js.map +1 -1
- package/dist/safety/index.d.ts +2 -2
- package/dist/safety/index.js +1 -1
- package/dist/safety/index.js.map +1 -1
- package/dist/safety/safetyController.js +675 -165
- package/dist/safety/safetyController.js.map +1 -1
- package/dist/scenarios/scenarioBundle.js +204 -71
- package/dist/scenarios/scenarioBundle.js.map +1 -1
- package/dist/scenarios/scenarioStore.js +88 -29
- package/dist/scenarios/scenarioStore.js.map +1 -1
- package/dist/security/headerSanitizer.js +52 -10
- package/dist/security/headerSanitizer.js.map +1 -1
- package/dist/security/secrets.js +10 -5
- package/dist/security/secrets.js.map +1 -1
- package/dist/server/accessControl.js +37 -10
- package/dist/server/accessControl.js.map +1 -1
- package/dist/server/createServer.js +1 -1
- package/dist/server/createServer.js.map +1 -1
- package/dist/server/eventsStore.js +15 -5
- package/dist/server/eventsStore.js.map +1 -1
- package/dist/server/routes.js +61 -19
- package/dist/server/routes.js.map +1 -1
- package/dist/server/sse.js +1 -1
- package/dist/server/sse.js.map +1 -1
- package/dist/setup/sdkDetector.js +7 -2
- package/dist/setup/sdkDetector.js.map +1 -1
- package/dist/setup/setupGenerator.js +136 -48
- package/dist/setup/setupGenerator.js.map +1 -1
- package/dist/state/stateExtractor.js +3 -1
- package/dist/state/stateExtractor.js.map +1 -1
- package/dist/state/stateResolver.js +10 -7
- package/dist/state/stateResolver.js.map +1 -1
- package/dist/state/stateStore.js +13 -4
- package/dist/state/stateStore.js.map +1 -1
- package/dist/storage/fileStore.js +12 -4
- package/dist/storage/fileStore.js.map +1 -1
- package/dist/teamControl/controlPlane.js +846 -174
- package/dist/teamControl/controlPlane.js.map +1 -1
- package/dist/teamControl/deployment.js +19 -5
- package/dist/teamControl/deployment.js.map +1 -1
- package/dist/teamControl/index.d.ts +4 -4
- package/dist/teamControl/index.js +2 -2
- package/dist/teamControl/index.js.map +1 -1
- package/dist/tests/testGenerator.js +15 -7
- package/dist/tests/testGenerator.js.map +1 -1
- package/dist/trust/index.d.ts +2 -2
- package/dist/trust/index.js +1 -1
- package/dist/trust/index.js.map +1 -1
- package/dist/trust/trustLadder.js +309 -63
- package/dist/trust/trustLadder.js.map +1 -1
- package/dist/worlds/index.d.ts +2 -2
- package/dist/worlds/index.js +1 -1
- package/dist/worlds/index.js.map +1 -1
- package/dist/worlds/worlds.js +364 -65
- package/dist/worlds/worlds.js.map +1 -1
- package/docs/assets/dashboard.png +0 -0
- package/docs/ci.md +49 -49
- package/docs/github-actions.md +84 -84
- package/docs/mcp.md +58 -52
- package/docs/policy.md +63 -61
- package/docs/providers/authoring-packs.md +180 -175
- package/docs/providers/stripe-core-pack.md +84 -82
- package/docs/releases/README.md +13 -0
- package/docs/security/action-gateway-threat-model.md +34 -34
- package/docs/security/action-ledger-incident-replay-threat-model.md +42 -42
- package/docs/security/approval-inbox-threat-model.md +35 -35
- package/docs/security/credential-broker-threat-model.md +52 -52
- package/docs/security/egress-threat-model.md +126 -126
- package/docs/security/inventory-threat-model.md +104 -104
- package/docs/security/kill-switch-budgets-threat-model.md +37 -37
- package/docs/security/reliability-threat-model.md +111 -111
- package/docs/security/trust-ladder-threat-model.md +33 -33
- package/docs/telemetry.md +14 -0
- package/docs/usage.md +680 -571
- package/examples/README.md +10 -10
- package/examples/agent-instructions/README.md +39 -39
- package/examples/ci-smoke/README.md +21 -21
- package/examples/ci-smoke/ghostapi.policy.yaml +22 -22
- package/examples/ci-smoke/package.json +9 -9
- package/examples/ci-smoke/production-egress.mjs +4 -2
- package/examples/ci-smoke/safe.mjs +21 -17
- package/examples/evals/README.md +24 -24
- package/examples/evals/retry-after.eval.json +71 -52
- package/examples/generic-rest/README.md +27 -27
- package/examples/github-fetch/README.md +38 -35
- package/examples/openai-streaming/README.md +16 -16
- package/examples/openai-streaming/streaming-tool-call.mjs +44 -31
- package/examples/policy/ghostapi.policy.yaml +27 -27
- package/examples/record-replay/README.md +19 -19
- package/examples/record-replay/replay-requests.json +22 -22
- package/examples/record-replay/stripe-checkout.har.json +30 -30
- package/examples/resend-node/README.md +22 -22
- package/examples/stripe-node/README.md +35 -35
- package/examples/stripe-node/checkout-flow.mjs +87 -61
- package/examples/twilio-node/README.md +21 -21
- package/examples/worlds/README.md +19 -19
- package/examples/worlds/subscription-recovery.mjs +21 -12
- package/package.json +28 -6
- package/dist/landing/assets/index-BXR41fAD.css +0 -1
- package/dist/landing/assets/index-CxWsopzP.css +0 -1
- package/dist/landing/assets/index-D8_ggMRE.js +0 -55
- package/dist/landing/assets/index-DZlpyhqd.js +0 -55
- package/dist/landing/assets/index-Dk-Xezs3.js +0 -55
- package/dist/landing/index.html +0 -15
- package/dist/landing/landing.d.ts +0 -3
- package/dist/landing/landing.js +0 -12
- package/dist/landing/landing.js.map +0 -1
- package/docs/commercial/README.md +0 -29
- package/docs/commercial/data-inventory.md +0 -36
- package/docs/commercial/manual-invoicing.md +0 -44
- package/docs/commercial/metrics.md +0 -51
- package/docs/commercial/pricing.md +0 -103
- package/docs/commercial/privacy-policy-draft.md +0 -41
- package/docs/commercial/terms-topics-for-counsel.md +0 -51
- package/docs/design-partners/README.md +0 -52
- package/docs/design-partners/demo-narratives.md +0 -33
- package/docs/design-partners/design-partner-offer.md +0 -39
- package/docs/design-partners/discovery-questions.md +0 -28
- package/docs/design-partners/feedback-capture-template.md +0 -48
- package/docs/design-partners/icp-one-pager.md +0 -43
- package/docs/design-partners/onboarding-checklist.md +0 -33
- package/docs/design-partners/pilot-success-criteria.md +0 -27
- package/docs/design-partners/pricing-interview-script.md +0 -18
- package/docs/design-partners/telemetry-plan.md +0 -48
- package/docs/development/baseline.md +0 -114
- package/docs/development/onboarding-smoke.md +0 -37
- package/docs/development/verification-0.1.8.md +0 -25
- package/docs/enterprise-product-roadmap-ru.md +0 -1879
- package/docs/fundraising/README.md +0 -87
- package/docs/fundraising/data-room-checklist.md +0 -72
- package/docs/fundraising/demo-script.md +0 -52
- package/docs/fundraising/design-partners-50.md +0 -74
- package/docs/fundraising/launch-posts.md +0 -37
- package/docs/fundraising/metrics-and-evidence.md +0 -30
- package/docs/fundraising/roadmap-12-month.md +0 -25
- package/docs/fundraising/technical-due-diligence-index.md +0 -37
- package/docs/fundraising/yc-application.md +0 -25
- package/docs/hosted-pilot.md +0 -111
- package/docs/operations/disaster-recovery-runbook.md +0 -81
- package/docs/operations/kill-switch-runbook.md +0 -32
- package/docs/release-checklist.md +0 -83
- package/docs/release-migration-and-rollback.md +0 -63
- package/docs/release-readiness.md +0 -39
- package/docs/team-control-plane.md +0 -72
package/docs/policy.md
CHANGED
|
@@ -1,61 +1,63 @@
|
|
|
1
|
-
# Policy As Code
|
|
2
|
-
|
|
3
|
-
GhostAPI reads one local, versioned YAML policy. It has no remote includes, environment-variable interpolation, templates, or executable expressions.
|
|
4
|
-
|
|
5
|
-
Copy [`examples/policy/ghostapi.policy.yaml`](../examples/policy/ghostapi.policy.yaml) into a project as `ghostapi.policy.yaml`, then validate it:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
ghostapi policy validate
|
|
9
|
-
ghostapi policy explain network api.stripe.com --provider stripe
|
|
10
|
-
ghostapi policy explain stripe.card_declined
|
|
11
|
-
ghostapi policy explain report 0 0 0
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
`ghostapi run --policy ghostapi.policy.yaml -- <command>` loads and validates the file once before any namespace preflight or target spawn. The run evidence records only the policy SHA-256 and required scenario IDs, not policy file content or command arguments. Policy changes during a run do not reload or alter that run.
|
|
15
|
-
|
|
16
|
-
`ghostapi evidence generate --policy ghostapi.policy.yaml --ci` evaluates required scenarios and report thresholds against the generated evidence artifact. Pass `--contract-baseline` and `--contract-candidate` to include contract drift. CI mode exits non-zero when required scenarios are missing, production-egress, forbidden-credential, or breaking-contract thresholds are exceeded, or other fail findings are present.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- `network.
|
|
48
|
-
- `
|
|
49
|
-
- `
|
|
50
|
-
- `
|
|
51
|
-
- `
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
1
|
+
# Policy As Code
|
|
2
|
+
|
|
3
|
+
GhostAPI reads one local, versioned YAML policy. It has no remote includes, environment-variable interpolation, templates, or executable expressions.
|
|
4
|
+
|
|
5
|
+
Copy [`examples/policy/ghostapi.policy.yaml`](../examples/policy/ghostapi.policy.yaml) into a project as `ghostapi.policy.yaml`, then validate it:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ghostapi policy validate
|
|
9
|
+
ghostapi policy explain network api.stripe.com --provider stripe
|
|
10
|
+
ghostapi policy explain stripe.card_declined
|
|
11
|
+
ghostapi policy explain report 0 0 0
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`ghostapi run --policy ghostapi.policy.yaml -- <command>` loads and validates the file once before any namespace preflight or target spawn. The run evidence records only the policy SHA-256 and required scenario IDs, not policy file content or command arguments. Policy changes during a run do not reload or alter that run.
|
|
15
|
+
|
|
16
|
+
`ghostapi evidence generate --policy ghostapi.policy.yaml --ci` evaluates required scenarios and report thresholds against the generated evidence artifact. Pass `--contract-baseline` and `--contract-candidate` to include contract drift. CI mode exits non-zero when required scenarios are missing, production-egress, forbidden-credential, or breaking-contract thresholds are exceeded, or other fail findings are present.
|
|
17
|
+
|
|
18
|
+
Schema-v1 network rules provide policy decisions and report classification; they do not configure a host firewall, intercept DNS, or transparently proxy arbitrary traffic. The current Linux launcher is loopback-only and rejects external allow-host requests.
|
|
19
|
+
|
|
20
|
+
## Schema V1
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
version: 1
|
|
24
|
+
network:
|
|
25
|
+
default: deny
|
|
26
|
+
allow:
|
|
27
|
+
- host: localhost
|
|
28
|
+
- provider: stripe
|
|
29
|
+
deny:
|
|
30
|
+
- host: api.stripe.com
|
|
31
|
+
productionHosts:
|
|
32
|
+
- "*.stripe.com"
|
|
33
|
+
credentials:
|
|
34
|
+
forbid:
|
|
35
|
+
- sk_live_*
|
|
36
|
+
requiredScenarios:
|
|
37
|
+
- stripe-payment-intent-card-declined
|
|
38
|
+
enforcement:
|
|
39
|
+
allowedModes:
|
|
40
|
+
- linux-network-namespace
|
|
41
|
+
reports:
|
|
42
|
+
maxProductionEgressAttempts: 0
|
|
43
|
+
maxForbiddenCredentialMatches: 0
|
|
44
|
+
maxBreakingContractChanges: 0
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- `network.default`: `allow` or `deny` when no rule matches.
|
|
48
|
+
- `network.allow` and `network.deny`: rules contain exactly one `host` or `provider` field.
|
|
49
|
+
- `network.productionHosts`: classifies hostnames for decision traces and CI/report evaluation.
|
|
50
|
+
- `credentials.forbid`: bounded `*` globs matched against an explicit input; GhostAPI never expands environment variables in policy.
|
|
51
|
+
- `requiredScenarios`: scenario IDs the evidence report must mark complete.
|
|
52
|
+
- `enforcement.allowedModes`: currently `linux-network-namespace` or `proxy-guidance`.
|
|
53
|
+
- `reports`: maximum allowed production-egress attempts, forbidden-credential matches, and breaking contract changes for a report decision. `maxBreakingContractChanges` defaults to `0` when omitted by an existing policy.
|
|
54
|
+
|
|
55
|
+
## Precedence And Limits
|
|
56
|
+
|
|
57
|
+
For a network decision, a matching `network.deny` rule always wins over a matching `network.allow` rule. Otherwise `network.default` decides. `ghostapi policy explain` prints the selected rule and decision trace.
|
|
58
|
+
|
|
59
|
+
Policies are limited to 128 KiB and list fields to 200 entries. Unknown fields, duplicate YAML keys, unsupported versions, anchors/aliases, interpolation syntax, path traversal, symlink policy files and multiple YAML documents are rejected with a path-aware error.
|
|
60
|
+
|
|
61
|
+
## Migration
|
|
62
|
+
|
|
63
|
+
Schema versions are exact. GhostAPI does not coerce or silently upgrade an unknown version. A future version must add an explicit migration command that reads one known old version, emits a new file for review, and requires a separate validation step. It must never rewrite a policy while `ghostapi run` is active.
|
|
@@ -1,175 +1,180 @@
|
|
|
1
|
-
# Authoring Provider Packs
|
|
2
|
-
|
|
3
|
-
Provider packs are the versioned contract layer for provider-specific behavior in GhostAPI. Resend and Stripe are migrated built-in packs. Twilio, GitHub, Discord, and OpenAI remain on the legacy adapter path until they can be migrated in small reviewed changes. Generic REST remains the fallback.
|
|
4
|
-
|
|
5
|
-
## Scope And Trust Boundary
|
|
6
|
-
|
|
7
|
-
Provider packs are built-in TypeScript modules compiled with GhostAPI. GhostAPI does not load uploaded, downloaded, or third-party executable provider code.
|
|
8
|
-
|
|
9
|
-
A pack receives only explicit inputs:
|
|
10
|
-
|
|
11
|
-
- detection receives a normalized path only;
|
|
12
|
-
- parsing, validation, and handling receive the sanitized `NormalizedRequest`;
|
|
13
|
-
- clock, ID generation, and a read-only state snapshot require explicit runtime capabilities;
|
|
14
|
-
- no network, filesystem, environment, or secret capability is available to a pack.
|
|
15
|
-
|
|
16
|
-
The source regression test rejects pack modules that import Node network/filesystem modules or access `process.env` or `fetch`. This is a maintenance boundary, not a secure JavaScript sandbox. Do not advertise arbitrary plugin isolation.
|
|
17
|
-
|
|
18
|
-
## Public Interfaces
|
|
19
|
-
|
|
20
|
-
The stable authoring surface is exported from `src/index.ts`:
|
|
21
|
-
|
|
22
|
-
- `ProviderPack`;
|
|
23
|
-
- `ProviderPackManifest`;
|
|
24
|
-
- `ProviderConformanceFixture`;
|
|
25
|
-
- `ProviderRuntime` and `ProviderRuntimeCapabilities`;
|
|
26
|
-
- `ProviderScenario` and `ProviderScenarioStep`;
|
|
27
|
-
- `ProviderWebhookHook`;
|
|
28
|
-
- `createProviderRuntime()`;
|
|
29
|
-
- `runProviderPackConformance()`.
|
|
30
|
-
|
|
31
|
-
The request pipeline, registry lookup, prepared execution object, response headers, state persistence, cache, Fault Lab, dashboard events, and scenario persistence are internal interfaces. Packs must not import stores or server modules directly.
|
|
32
|
-
|
|
33
|
-
## Required Contract
|
|
34
|
-
|
|
35
|
-
Every pack declares:
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
export const examplePack: ProviderPack = {
|
|
39
|
-
name: "example",
|
|
40
|
-
displayName: "Example",
|
|
41
|
-
manifest: {
|
|
42
|
-
schemaVersion: 1,
|
|
43
|
-
name: "example",
|
|
44
|
-
displayName: "Example",
|
|
45
|
-
implementation: "pack",
|
|
46
|
-
packVersion: "1.0.0",
|
|
47
|
-
apiVersions: { default: "v1", supported: ["v1"] },
|
|
48
|
-
capabilities: {
|
|
49
|
-
detection: true,
|
|
50
|
-
requestParsing: true,
|
|
51
|
-
validation: true,
|
|
52
|
-
deterministicResponses: true,
|
|
53
|
-
stateTransitions: true,
|
|
54
|
-
providerErrors: true,
|
|
55
|
-
scenarios: false,
|
|
56
|
-
webhooks: false,
|
|
57
|
-
conformanceFixtures: true
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
detection: {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
|
171
|
-
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
1
|
+
# Authoring Provider Packs
|
|
2
|
+
|
|
3
|
+
Provider packs are the versioned contract layer for provider-specific behavior in GhostAPI. Resend and Stripe are migrated built-in packs. Twilio, GitHub, Discord, and OpenAI remain on the legacy adapter path until they can be migrated in small reviewed changes. Generic REST remains the fallback.
|
|
4
|
+
|
|
5
|
+
## Scope And Trust Boundary
|
|
6
|
+
|
|
7
|
+
Provider packs are built-in TypeScript modules compiled with GhostAPI. GhostAPI does not load uploaded, downloaded, or third-party executable provider code.
|
|
8
|
+
|
|
9
|
+
A pack receives only explicit inputs:
|
|
10
|
+
|
|
11
|
+
- detection receives a normalized path only;
|
|
12
|
+
- parsing, validation, and handling receive the sanitized `NormalizedRequest`;
|
|
13
|
+
- clock, ID generation, and a read-only state snapshot require explicit runtime capabilities;
|
|
14
|
+
- no network, filesystem, environment, or secret capability is available to a pack.
|
|
15
|
+
|
|
16
|
+
The source regression test rejects pack modules that import Node network/filesystem modules or access `process.env` or `fetch`. This is a maintenance boundary, not a secure JavaScript sandbox. Do not advertise arbitrary plugin isolation.
|
|
17
|
+
|
|
18
|
+
## Public Interfaces
|
|
19
|
+
|
|
20
|
+
The stable authoring surface is exported from `src/index.ts`:
|
|
21
|
+
|
|
22
|
+
- `ProviderPack`;
|
|
23
|
+
- `ProviderPackManifest`;
|
|
24
|
+
- `ProviderConformanceFixture`;
|
|
25
|
+
- `ProviderRuntime` and `ProviderRuntimeCapabilities`;
|
|
26
|
+
- `ProviderScenario` and `ProviderScenarioStep`;
|
|
27
|
+
- `ProviderWebhookHook`;
|
|
28
|
+
- `createProviderRuntime()`;
|
|
29
|
+
- `runProviderPackConformance()`.
|
|
30
|
+
|
|
31
|
+
The request pipeline, registry lookup, prepared execution object, response headers, state persistence, cache, Fault Lab, dashboard events, and scenario persistence are internal interfaces. Packs must not import stores or server modules directly.
|
|
32
|
+
|
|
33
|
+
## Required Contract
|
|
34
|
+
|
|
35
|
+
Every pack declares:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
export const examplePack: ProviderPack = {
|
|
39
|
+
name: "example",
|
|
40
|
+
displayName: "Example",
|
|
41
|
+
manifest: {
|
|
42
|
+
schemaVersion: 1,
|
|
43
|
+
name: "example",
|
|
44
|
+
displayName: "Example",
|
|
45
|
+
implementation: "pack",
|
|
46
|
+
packVersion: "1.0.0",
|
|
47
|
+
apiVersions: { default: "v1", supported: ["v1"] },
|
|
48
|
+
capabilities: {
|
|
49
|
+
detection: true,
|
|
50
|
+
requestParsing: true,
|
|
51
|
+
validation: true,
|
|
52
|
+
deterministicResponses: true,
|
|
53
|
+
stateTransitions: true,
|
|
54
|
+
providerErrors: true,
|
|
55
|
+
scenarios: false,
|
|
56
|
+
webhooks: false,
|
|
57
|
+
conformanceFixtures: true,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
detection: {
|
|
61
|
+
priority: 100,
|
|
62
|
+
matches: ({ path }) => path.startsWith("/example"),
|
|
63
|
+
},
|
|
64
|
+
parseRequest: (request) => request.body,
|
|
65
|
+
selectApiVersion: () => ({ version: "v1" }),
|
|
66
|
+
validate: () => null,
|
|
67
|
+
handleDeterministic: ({ runtime }) => ({
|
|
68
|
+
status: 200,
|
|
69
|
+
headers: { "content-type": "application/json" },
|
|
70
|
+
body: {
|
|
71
|
+
id: runtime.requireCapability("idGenerator").create("example_mock"),
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
createResponseHeaders: () => ({}),
|
|
75
|
+
transitionState: () => null,
|
|
76
|
+
stateful: false,
|
|
77
|
+
formatError: (details) => ({ error: { message: details.message } }),
|
|
78
|
+
promptHints: [],
|
|
79
|
+
scenarios: [],
|
|
80
|
+
conformanceFixtures: [],
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The manifest is returned by `GET /api/providers`, shown in dashboard provider filters, and printed by `ghostapi providers list` and `ghostapi providers inspect <name>`.
|
|
85
|
+
|
|
86
|
+
## API Version Selection
|
|
87
|
+
|
|
88
|
+
Pack API versions are GhostAPI compatibility versions, not an automatic claim of full parity with a provider's live API. A pack must:
|
|
89
|
+
|
|
90
|
+
1. declare one default version and all supported versions;
|
|
91
|
+
2. select a version before request validation;
|
|
92
|
+
3. return a provider-shaped `ProviderErrorDetails` for unsupported explicit versions;
|
|
93
|
+
4. include version-sensitive request headers in cache identity;
|
|
94
|
+
5. change `packVersion` when pack behavior changes and add a new API version when the simulated contract changes incompatibly.
|
|
95
|
+
|
|
96
|
+
The Resend pack accepts `x-ghostapi-api-version: v1`. Successful responses include:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
x-ghostapi-provider-pack: resend@1.0.0
|
|
100
|
+
x-ghostapi-api-version: v1
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Determinism
|
|
104
|
+
|
|
105
|
+
Do not call `Date.now()`, `new Date()`, random generators, environment variables, or external services inside a pack. Request runtime capabilities explicitly:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const now = runtime.requireCapability("clock").now();
|
|
109
|
+
const id = runtime.requireCapability("idGenerator").create("item_mock");
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Tests must inject fixed implementations with `createProviderRuntime()`. `createResponseHeaders()` can add deterministic provider headers such as Stripe request IDs to successful or early-error responses. Asking for an undeclared capability fails with `Unknown provider capability: <name>`.
|
|
113
|
+
|
|
114
|
+
## Validation And Errors
|
|
115
|
+
|
|
116
|
+
`parseRequest()` converts the sanitized normalized request into the provider's internal request shape. `validate()` returns `null` or `ProviderErrorDetails`. Core formats the details through the registered provider error formatter.
|
|
117
|
+
|
|
118
|
+
Keep validation order stable when migrating a public route. Error status, field names, messages, and provider shape are observable behavior.
|
|
119
|
+
|
|
120
|
+
## State Transitions
|
|
121
|
+
|
|
122
|
+
`transitionState()` describes persistence but does not write it. Core owns storage and requires keys to stay in the exact `<provider>:<id>` namespace. A pack that declares `stateful: true` executes under one atomic local-state transaction and can inspect the injected read-only snapshot while deciding its response. It still cannot access a store directly.
|
|
123
|
+
|
|
124
|
+
A transition must be derived from the handled response and must not read ambient state. The conformance fixture should assert both the key and value. Core rejects cross-provider or empty keys before persistence.
|
|
125
|
+
|
|
126
|
+
## Scenarios And Webhooks
|
|
127
|
+
|
|
128
|
+
Pack scenarios use the shared `ProviderScenario` shape and are merged into the existing scenario registry. Scenario replay still installs deterministic method/path behaviors and runs before faults, validation, state, cache, and generation.
|
|
129
|
+
|
|
130
|
+
`ProviderWebhookHook` is part of the authoring vocabulary, but no built-in pack currently advertises webhook capability. Do not set `webhooks: true` until event synthesis, signing, delivery timing, retries, and failure semantics have tests.
|
|
131
|
+
|
|
132
|
+
## Conformance Fixtures
|
|
133
|
+
|
|
134
|
+
Every migrated pack must provide at least one fixture that exercises its main mutation or read flow. Run it through the common harness:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const runtime = createProviderRuntime({
|
|
138
|
+
clock: { now: () => new Date("2026-08-06T12:00:00.000Z") },
|
|
139
|
+
idGenerator: { create: (prefix) => `${prefix}_fixture` },
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
runProviderPackConformance(examplePack, runtime);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The harness:
|
|
146
|
+
|
|
147
|
+
1. selects an API version;
|
|
148
|
+
2. parses and validates the fixture request;
|
|
149
|
+
3. generates a deterministic response;
|
|
150
|
+
4. runs the fixture response assertion;
|
|
151
|
+
5. computes and validates the state transition;
|
|
152
|
+
6. runs the fixture transition assertion.
|
|
153
|
+
|
|
154
|
+
Malformed responses and wrong state keys must fail the harness.
|
|
155
|
+
|
|
156
|
+
## Adding Or Migrating A Pack
|
|
157
|
+
|
|
158
|
+
1. Add one pack under `src/providers/packs/`.
|
|
159
|
+
2. Register it in the ordered built-in pack list in `src/providers/registry.ts`.
|
|
160
|
+
3. Remove only that provider's legacy detection, validation, generation, prompt, and scenario branches.
|
|
161
|
+
4. Preserve route detection precedence and generic REST fallback.
|
|
162
|
+
5. Add conformance, provider regression, manifest API, state, cache, and provider-shaped error tests.
|
|
163
|
+
6. Run `npm run typecheck`, `npm test`, and `npm run build`.
|
|
164
|
+
7. Inspect built CLI output and package contents before release.
|
|
165
|
+
|
|
166
|
+
## Migration Plan
|
|
167
|
+
|
|
168
|
+
The remaining providers should move one at a time:
|
|
169
|
+
|
|
170
|
+
| Order | Provider | Migration focus | Deferred risk |
|
|
171
|
+
| ----- | -------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
172
|
+
| 1 | Twilio | Form parsing, validation, SID generation, error shape | Message status transitions and callbacks |
|
|
173
|
+
| 2 | GitHub | Version header, deterministic issue/repository shapes, scenarios | Pagination and conditional requests |
|
|
174
|
+
| 3 | OpenAI | API version policy, typed response families, list state | Streaming and token accounting |
|
|
175
|
+
| 4 | Discord | Route/body detection and message shapes | Webhook and interaction semantics |
|
|
176
|
+
| Done | Stripe | Core pack for customers, payment intents, payment methods, checkout sessions, refunds, pagination, and idempotency | Webhooks, subscriptions, invoices, disputes, and broader state-machine parity |
|
|
177
|
+
|
|
178
|
+
Stripe now demonstrates the deeper stateful pack path. See [`stripe-core-pack.md`](stripe-core-pack.md) for the supported contract and limits.
|
|
179
|
+
|
|
180
|
+
Generic REST should not become a provider pack. It remains the explicit fallback so unknown APIs continue to work without pretending to have a provider contract.
|