@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
|
@@ -1,82 +1,84 @@
|
|
|
1
|
-
# Stripe Core Pack
|
|
2
|
-
|
|
3
|
-
The built-in Stripe core pack is a deterministic local simulation for the most common payment workflows. It is not full Stripe compatibility and it never makes outbound network requests.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
1
|
+
# Stripe Core Pack
|
|
2
|
+
|
|
3
|
+
The built-in Stripe core pack is a deterministic local simulation for the most common payment workflows. It is not full Stripe compatibility and it never makes outbound network requests.
|
|
4
|
+
|
|
5
|
+
The locked compatibility lane exercises the official Stripe Node SDK `22.6.0`. Compatibility is version-scoped; it is not a guarantee for every SDK or Stripe API version.
|
|
6
|
+
|
|
7
|
+
## Version And Verification
|
|
8
|
+
|
|
9
|
+
- Verified against Stripe's official API reference and Stripe Node SDK behavior on 2026-08-06.
|
|
10
|
+
- GhostAPI compatibility API version: `2026-02-25.clover`.
|
|
11
|
+
- Pack version: `1.1.0`.
|
|
12
|
+
- Successful pack responses include `x-ghostapi-provider-pack: stripe@1.1.0`, `stripe-version: 2026-02-25.clover`, and a deterministic `request-id`.
|
|
13
|
+
|
|
14
|
+
The version is an explicit GhostAPI compatibility contract, not a claim that all live Stripe endpoints or fields are supported.
|
|
15
|
+
|
|
16
|
+
## Supported Operations
|
|
17
|
+
|
|
18
|
+
| Resource | Operations |
|
|
19
|
+
| ----------------- | ------------------------------------------------------------- |
|
|
20
|
+
| Customers | Create, retrieve, update, delete, list |
|
|
21
|
+
| Payment Intents | Create, retrieve, update, confirm, list |
|
|
22
|
+
| Payment Methods | Create minimal `card` method, retrieve, list |
|
|
23
|
+
| Checkout Sessions | Create, retrieve, list |
|
|
24
|
+
| Refunds | Create, retrieve, list |
|
|
25
|
+
| Products | Create, retrieve, update, list |
|
|
26
|
+
| Prices | Create recurring or one-time prices, retrieve, update, list |
|
|
27
|
+
| Subscriptions | Create, retrieve, update, cancel, local `renew` control, list |
|
|
28
|
+
| Invoices | Retrieve, pay, void, list |
|
|
29
|
+
| Events | List, retrieve, and local signed delivery |
|
|
30
|
+
|
|
31
|
+
List endpoints return Stripe-shaped `{ object: "list", data, has_more, url }` responses and accept `limit`, `starting_after`, and `ending_before` cursors.
|
|
32
|
+
|
|
33
|
+
The pack accepts form-encoded nested parameters such as `metadata[source]=sdk` and `line_items[0][price_data][unit_amount]=2500`, as emitted by the Stripe Node SDK. JSON bodies are accepted for direct local clients.
|
|
34
|
+
|
|
35
|
+
## Determinism And State
|
|
36
|
+
|
|
37
|
+
Objects receive deterministic IDs, timestamps, and request IDs when a fixed runtime clock and ID generator are injected in tests. Normal runtime IDs remain unique across requests. Stateful requests run under GhostAPI's local atomic state transaction; the pack does not access storage itself.
|
|
38
|
+
|
|
39
|
+
`Idempotency-Key` is represented only by a SHA-256-derived local digest in events and state. A repeated mutation with the same key and parameters returns the original response with `x-ghostapi-idempotency: REPLAY`. Reusing the key with different parameters returns a Stripe-shaped `idempotency_error`. Receipts expire after 24 hours, allowing a new mutation for the same key after the local retention window.
|
|
40
|
+
|
|
41
|
+
## Billing Lifecycle
|
|
42
|
+
|
|
43
|
+
Subscriptions use one recurring Price. Creating with `trial_period_days` creates a `trialing` subscription; `POST /v1/subscriptions/:id/renew` is a GhostAPI-only local test control that advances it. A normal renewal produces an Invoice, succeeded Payment Intent, and `active` subscription. `pm_card_chargeDeclined` produces a Stripe `card_error`, preserves an open Invoice, and sets the subscription to `past_due`; `POST /v1/invoices/:id/pay` can recover it. Cancellation marks the subscription `canceled`. Refunds create a `charge.refunded` event and update the local Payment Intent refund total.
|
|
44
|
+
|
|
45
|
+
## Webhook Testing
|
|
46
|
+
|
|
47
|
+
State transitions create persisted Stripe-shaped Events for subscription, invoice, payment-intent, and refund lifecycle changes. GhostAPI deliberately does not accept arbitrary webhook target URLs and never sends outbound webhook HTTP requests. Instead, tests pull a raw signed payload from:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
GET /v1/events/:event_id/deliver?delivery_mode=normal|duplicate|delayed|out_of_order|invalid_signature
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The response includes `stripe-signature`, generated with HMAC-SHA256 over `timestamp.rawPayload`. The default local-only secret is `whsec_ghostapi_local_test_secret`; set `GHOSTAPI_STRIPE_WEBHOOK_SECRET` to use another test secret. The secret is not stored in state, events, scenarios, or responses. `duplicate` reliably returns the same event ID and payload on repeat calls, `delayed` accepts bounded `delay_ms` (0-10000), `out_of_order` reverses the event-list ordering, and `invalid_signature` corrupts the signature. Use the official `stripe.webhooks.constructEvent` verifier against the raw response body.
|
|
54
|
+
|
|
55
|
+
Rate-limit (`429` + `Retry-After`), bounded delay/timeout simulation, and `5xx` behavior remain controlled through GhostAPI Fault Lab. These are injected before pack execution, so a client retry with an idempotency key exercises the normal atomic replay path after the fault is disabled.
|
|
56
|
+
|
|
57
|
+
## Test Card Outcomes
|
|
58
|
+
|
|
59
|
+
Use the Stripe test payment-method identifier `pm_card_chargeDeclined` (or legacy `tok_chargeDeclined`) when creating or confirming a Payment Intent to receive:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"error": {
|
|
64
|
+
"type": "card_error",
|
|
65
|
+
"code": "card_declined",
|
|
66
|
+
"decline_code": "generic_decline"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
No PAN or CVC is required. If a direct client submits card-like fields, GhostAPI masks them before event or snapshot persistence. The returned synthetic Payment Method exposes only fixed non-sensitive card metadata such as `last4`.
|
|
72
|
+
|
|
73
|
+
## Deliberate Limits
|
|
74
|
+
|
|
75
|
+
- Disputes, Connect, payment links, Setup Intents, hosted Checkout, tax, proration, dunning, smart retries, and most Stripe APIs remain unsupported.
|
|
76
|
+
- Unsupported operations return a diagnostic `invalid_request_error`; GhostAPI does not generate a fake success.
|
|
77
|
+
- Checkout Sessions are local objects. Their returned URL is a local placeholder and not a hosted checkout page.
|
|
78
|
+
- Payment Intent confirmation has a simplified state model: normal confirmation succeeds; the documented decline token fails.
|
|
79
|
+
- Refunds support `payment_intent` or `charge` input, but only validate a referenced Payment Intent when one is supplied.
|
|
80
|
+
- No live keys, PANs, CVCs, provider credentials, or real network traffic are retained or used.
|
|
81
|
+
|
|
82
|
+
## Runnable SDK Example
|
|
83
|
+
|
|
84
|
+
Start GhostAPI and run `examples/stripe-node/checkout-flow.mjs`. The example configures the official Node SDK with its documented host, port, protocol, and API-version client options, then verifies a locally delivered webhook using the SDK; no SDK source patch is required.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Release Evidence
|
|
2
|
+
|
|
3
|
+
GhostAPI release evidence is tied to an exact public commit and generated by the release workflow.
|
|
4
|
+
|
|
5
|
+
For each release, verify:
|
|
6
|
+
|
|
7
|
+
- the annotated Git tag is `v<package.json version>` and points to the published commit;
|
|
8
|
+
- CI, package smoke tests, and Linux egress enforcement checks passed for that commit;
|
|
9
|
+
- the GitHub Release contains the exact tested npm tarball, `SHA256SUMS`, and a CycloneDX SBOM;
|
|
10
|
+
- the tarball has a GitHub build-provenance attestation;
|
|
11
|
+
- npm shows provenance and its `gitHead` matches the tagged commit.
|
|
12
|
+
|
|
13
|
+
Historical `0.1.x` artifacts may not satisfy this complete chain and retain their immutable original npm `gitHead` metadata. A reviewed metadata-only history correction was applied before `v0.2.0`; PR #20 records the unchanged trees, messages, and dates. The first release intended to use the complete workflow is `v0.2.0`.
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
# Synthetic Action Gateway Threat Model
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
The Session 23 action gateway is a local, data-only implementation of the shared action contract. Its only executor is `ghostapi-synthetic`, which mutates an existing local synthetic world. It has no provider HTTP client, credential input, environment-secret lookup, account configuration, shell execution, webhook delivery, or cloud transport.
|
|
6
|
-
|
|
7
|
-
It is not a production gateway. Real provider accounts, credentials, sandbox accounts, provider calls, external messages, money movement, deployments, and deletes are out of scope until the Session 23 entry gate has documented design-partner requirements, a separate test account, an approved threat model, and explicit owner authorization.
|
|
8
|
-
|
|
9
|
-
## Trust Boundaries
|
|
10
|
-
|
|
11
|
-
- Agent input: `ActionEnvelope` is untrusted data and is strictly schema-validated.
|
|
12
|
-
- Approval input: `ActionApproval` is structured data bound to the canonical SHA-256 action hash and carries Ed25519 provenance from an injected trusted key. A boolean approval, unsigned JSON, unknown key ID, or invalid signature is not accepted.
|
|
13
|
-
- Policy input: the current local policy is loaded again at submit and execute; its version and SHA-256 source hash must match the approved envelope.
|
|
14
|
-
- Identity input: the execution actor/workload pair must match the approved envelope immediately before side effect.
|
|
15
|
-
- Persistence: action records use a private local directory, per-action lock, atomic replacement, regular-file checks, byte bounds, and receipt-chain validation. This coordinates cooperating local processes only; it is not protection from a malicious same-user actor who can alter both state and runtime.
|
|
16
|
-
- Synthetic adapter: execution delegates only to the existing atomic synthetic-world workflow. It has no ambient network or credential capability.
|
|
17
|
-
|
|
18
|
-
## Invariants
|
|
19
|
-
|
|
20
|
-
- Canonical serialization sorts object keys and preserves array order. Any argument change changes the action hash and invalidates approval.
|
|
21
|
-
- An approver cannot equal the action actor or workload identity.
|
|
22
|
-
- Approval provenance is verified at submission and re-authenticated from the persisted approval immediately before execution. A missing or unavailable verifier fails closed.
|
|
23
|
-
- Action expiry, approval expiry, policy reference, actor identity, adapter support, and idempotency state are checked immediately before execution.
|
|
24
|
-
- Inbox-issued approvals additionally require verifier-backed durable inbox consumption state; possession of artifact JSON or a trusted public key alone does not authorize gateway execution.
|
|
25
|
-
- Receipts distinguish `requested`, `attempted`, `committed`, `verified`, and `failed`. Each receipt hashes the prior receipt hash plus its canonical content.
|
|
26
|
-
- An `attempted` action is reconciled with `verify` before any subsequent execution. A failed reconciliation is an unknown outcome and is never automatically retried.
|
|
27
|
-
- Duplicate action IDs with a changed envelope or approval are rejected. A verified or committed action returns its existing receipt without another synthetic side effect.
|
|
28
|
-
- Unsupported operations and unsupported compensation fail visibly. The API uses `compensate`, never `rollback`; the current synthetic adapter exposes no compensation.
|
|
29
|
-
|
|
30
|
-
## Remaining Limits
|
|
31
|
-
|
|
32
|
-
- Policy schema v1 does not yet express action-level authorization. The gateway rechecks the approved policy version/hash to prevent stale-policy execution; a later production policy extension must add an explicit action decision before exposing a non-synthetic adapter.
|
|
33
|
-
- Local receipt chaining is tamper-evident only while the local store and runtime are trusted. It is not an externally immutable ledger or a legal audit record.
|
|
34
|
-
- A future provider adapter must provide provider-specific idempotency proof, safe reconciliation for timeout ambiguity, credentials held behind a broker/gateway boundary, scoped grants, kill-switch/budget checks, durable audit evidence, and explicit compensation semantics before it can execute any real side effect.
|
|
1
|
+
# Synthetic Action Gateway Threat Model
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
The Session 23 action gateway is a local, data-only implementation of the shared action contract. Its only executor is `ghostapi-synthetic`, which mutates an existing local synthetic world. It has no provider HTTP client, credential input, environment-secret lookup, account configuration, shell execution, webhook delivery, or cloud transport.
|
|
6
|
+
|
|
7
|
+
It is not a production gateway. Real provider accounts, credentials, sandbox accounts, provider calls, external messages, money movement, deployments, and deletes are out of scope until the Session 23 entry gate has documented design-partner requirements, a separate test account, an approved threat model, and explicit owner authorization.
|
|
8
|
+
|
|
9
|
+
## Trust Boundaries
|
|
10
|
+
|
|
11
|
+
- Agent input: `ActionEnvelope` is untrusted data and is strictly schema-validated.
|
|
12
|
+
- Approval input: `ActionApproval` is structured data bound to the canonical SHA-256 action hash and carries Ed25519 provenance from an injected trusted key. A boolean approval, unsigned JSON, unknown key ID, or invalid signature is not accepted.
|
|
13
|
+
- Policy input: the current local policy is loaded again at submit and execute; its version and SHA-256 source hash must match the approved envelope.
|
|
14
|
+
- Identity input: the execution actor/workload pair must match the approved envelope immediately before side effect.
|
|
15
|
+
- Persistence: action records use a private local directory, per-action lock, atomic replacement, regular-file checks, byte bounds, and receipt-chain validation. This coordinates cooperating local processes only; it is not protection from a malicious same-user actor who can alter both state and runtime.
|
|
16
|
+
- Synthetic adapter: execution delegates only to the existing atomic synthetic-world workflow. It has no ambient network or credential capability.
|
|
17
|
+
|
|
18
|
+
## Invariants
|
|
19
|
+
|
|
20
|
+
- Canonical serialization sorts object keys and preserves array order. Any argument change changes the action hash and invalidates approval.
|
|
21
|
+
- An approver cannot equal the action actor or workload identity.
|
|
22
|
+
- Approval provenance is verified at submission and re-authenticated from the persisted approval immediately before execution. A missing or unavailable verifier fails closed.
|
|
23
|
+
- Action expiry, approval expiry, policy reference, actor identity, adapter support, and idempotency state are checked immediately before execution.
|
|
24
|
+
- Inbox-issued approvals additionally require verifier-backed durable inbox consumption state; possession of artifact JSON or a trusted public key alone does not authorize gateway execution.
|
|
25
|
+
- Receipts distinguish `requested`, `attempted`, `committed`, `verified`, and `failed`. Each receipt hashes the prior receipt hash plus its canonical content.
|
|
26
|
+
- An `attempted` action is reconciled with `verify` before any subsequent execution. A failed reconciliation is an unknown outcome and is never automatically retried.
|
|
27
|
+
- Duplicate action IDs with a changed envelope or approval are rejected. A verified or committed action returns its existing receipt without another synthetic side effect.
|
|
28
|
+
- Unsupported operations and unsupported compensation fail visibly. The API uses `compensate`, never `rollback`; the current synthetic adapter exposes no compensation.
|
|
29
|
+
|
|
30
|
+
## Remaining Limits
|
|
31
|
+
|
|
32
|
+
- Policy schema v1 does not yet express action-level authorization. The gateway rechecks the approved policy version/hash to prevent stale-policy execution; a later production policy extension must add an explicit action decision before exposing a non-synthetic adapter.
|
|
33
|
+
- Local receipt chaining is tamper-evident only while the local store and runtime are trusted. It is not an externally immutable ledger or a legal audit record.
|
|
34
|
+
- A future provider adapter must provide provider-specific idempotency proof, safe reconciliation for timeout ambiguity, credentials held behind a broker/gateway boundary, scoped grants, kill-switch/budget checks, durable audit evidence, and explicit compensation semantics before it can execute any real side effect.
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
# Local Action Ledger And Incident Replay Threat Model
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
The local action ledger is a typed API for turning an already persisted synthetic action record into a tenant-scoped, append-only timeline. It records hashes and bounded structured facts for intent, identity, policy decision, approval, credential-grant reference, attempts, provider receipt, verification, compensation status, and governance events.
|
|
6
|
-
|
|
7
|
-
It does not add a provider client, provider account, credential vault, HTTP transport, production execution path, production credential, hosted audit service, legal/compliance service, or immutable external storage. The current incident pipeline turns a ledger action into one local deterministic synthetic world plus one data-only scenario bundle. Replay uses the existing in-memory `ScenarioReplayer`; it makes no network request and cannot use original credentials.
|
|
8
|
-
|
|
9
|
-
## Integrity And Privacy
|
|
10
|
-
|
|
11
|
-
- Each tenant has its own SHA-256 genesis hash and ordered hash chain. Every entry binds its tenant, sequence, timestamp, action reference, stage, structured fields, and previous hash.
|
|
12
|
-
- Tenant metadata stores the current entry count and head hash. Verification detects modified content, reordered entries, removed entries, invalid links, and a mismatched head/count.
|
|
13
|
-
- The store is bounded, strict-schema validated, regular-file/non-symlink checked, serialized with the existing local file lock, and atomically replaced.
|
|
14
|
-
- Ledger values are scalar-only. Raw arguments, payloads, authorization, cookies, tokens, secret/password fields, email, phone, address, card, and body/payload fields are rejected. Action/resource/provider references are persisted only as stable IDs or SHA-256 hashes where the identifier could expose sensitive data.
|
|
15
|
-
- Export verifies the requested tenant chain first and returns entries only for the tenant authorized by the injected access authorizer. It contains no credential material or raw action payload.
|
|
16
|
-
|
|
17
|
-
## Outcome Semantics
|
|
18
|
-
|
|
19
|
-
- A `verified` ledger stage is emitted only from a gateway `verified` receipt.
|
|
20
|
-
- A failed receipt with `unknown_outcome` becomes `ambiguous` and `requires_reconciliation`; it is never relabeled successful.
|
|
21
|
-
- A committed receipt without a verified receipt remains unverified. The incident fixture reproduces this distinction locally with `409 requires_reconciliation` rather than inventing success.
|
|
22
|
-
- Credential use is a reference only: `grantIdHash`, credential version, or `not_used`. The ledger never receives or exports the underlying secret.
|
|
23
|
-
|
|
24
|
-
## Retention, Hold, And Deletion
|
|
25
|
-
|
|
26
|
-
- `configureRetention()` records a per-tenant retention policy. `appendEntry` enforces the store bound (`MAX_ENTRIES` 2,000): when the cap is reached, entries older than the tenant's `retentionDays` are rotated out and the tenant's hash chain is relinked to genesis — `previousHash`/`entryHash` are recomputed and `entryCount`/`headHash` updated, so a subsequent `verifyTenant` still passes. Rotation is bounded and never silent at the cap: if the store cannot be brought under `MAX_ENTRIES`, the append is rejected with an explicit retention-review error.
|
|
27
|
-
- Rotation is per-tenant and opt-in: a tenant without a `retentionDays` policy is never rotated (its chain remains strictly append-only), and a tenant under `setLegalHold(true)` is never rotated.
|
|
28
|
-
- `setLegalHold(true)` records an active local hold and blocks `requestDeletion()`.
|
|
29
|
-
- `requestDeletion()` records a request timestamp after the hold check. It does not erase entries, backups, or external copies and does not claim GDPR, SEC, HIPAA, or any other compliance behavior.
|
|
30
|
-
- A real retention/deletion workflow needs an approved retention schedule, backup lifecycle, legal authority, trusted identity, durable external evidence, and a cryptographically preserved anchor before destructive deletion can be designed.
|
|
31
|
-
|
|
32
|
-
## Claimed Basis And Verification
|
|
33
|
-
|
|
34
|
-
- `policy_decision` and `approval` stages echo caller-supplied decisions as `basis: "caller_claimed"` — they record what the caller asserted at admission time, not an independently verified policy/approval decision, and consumers must treat them as claims.
|
|
35
|
-
- `verifyTenant()` returns `tracked: false` with the tenant's genesis hash as head for a tenant that has no entries, and `tracked: true` for a tenant with entries, so "no ledger yet" is distinguishable from a broken or tampered chain.
|
|
36
|
-
|
|
37
|
-
## Trust Boundaries And Limits
|
|
38
|
-
|
|
39
|
-
- `LedgerAccessAuthorizer` is injected. The default authorizer denies everything. Test capability helpers are only local test utilities, not authentication or tenant isolation for a deployed service.
|
|
40
|
-
- Tenant isolation applies to calls that go through a correct injected authorizer. A malicious same-user actor who can replace the local state file and runtime is outside this local filesystem model.
|
|
41
|
-
- The chain is tamper-evident, not absolutely immutable. It does not defend against a compromised host, altered application code, deleted backups, an attacker who replaces both data and trusted head/anchor, distributed filesystems, or a dishonest clock.
|
|
42
|
-
- Sanitization is structural and pattern-based. Operators must inspect incident fixtures before sharing them; GhostAPI does not guarantee perfect anonymization.
|
|
1
|
+
# Local Action Ledger And Incident Replay Threat Model
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
The local action ledger is a typed API for turning an already persisted synthetic action record into a tenant-scoped, append-only timeline. It records hashes and bounded structured facts for intent, identity, policy decision, approval, credential-grant reference, attempts, provider receipt, verification, compensation status, and governance events.
|
|
6
|
+
|
|
7
|
+
It does not add a provider client, provider account, credential vault, HTTP transport, production execution path, production credential, hosted audit service, legal/compliance service, or immutable external storage. The current incident pipeline turns a ledger action into one local deterministic synthetic world plus one data-only scenario bundle. Replay uses the existing in-memory `ScenarioReplayer`; it makes no network request and cannot use original credentials.
|
|
8
|
+
|
|
9
|
+
## Integrity And Privacy
|
|
10
|
+
|
|
11
|
+
- Each tenant has its own SHA-256 genesis hash and ordered hash chain. Every entry binds its tenant, sequence, timestamp, action reference, stage, structured fields, and previous hash.
|
|
12
|
+
- Tenant metadata stores the current entry count and head hash. Verification detects modified content, reordered entries, removed entries, invalid links, and a mismatched head/count.
|
|
13
|
+
- The store is bounded, strict-schema validated, regular-file/non-symlink checked, serialized with the existing local file lock, and atomically replaced.
|
|
14
|
+
- Ledger values are scalar-only. Raw arguments, payloads, authorization, cookies, tokens, secret/password fields, email, phone, address, card, and body/payload fields are rejected. Action/resource/provider references are persisted only as stable IDs or SHA-256 hashes where the identifier could expose sensitive data.
|
|
15
|
+
- Export verifies the requested tenant chain first and returns entries only for the tenant authorized by the injected access authorizer. It contains no credential material or raw action payload.
|
|
16
|
+
|
|
17
|
+
## Outcome Semantics
|
|
18
|
+
|
|
19
|
+
- A `verified` ledger stage is emitted only from a gateway `verified` receipt.
|
|
20
|
+
- A failed receipt with `unknown_outcome` becomes `ambiguous` and `requires_reconciliation`; it is never relabeled successful.
|
|
21
|
+
- A committed receipt without a verified receipt remains unverified. The incident fixture reproduces this distinction locally with `409 requires_reconciliation` rather than inventing success.
|
|
22
|
+
- Credential use is a reference only: `grantIdHash`, credential version, or `not_used`. The ledger never receives or exports the underlying secret.
|
|
23
|
+
|
|
24
|
+
## Retention, Hold, And Deletion
|
|
25
|
+
|
|
26
|
+
- `configureRetention()` records a per-tenant retention policy. `appendEntry` enforces the store bound (`MAX_ENTRIES` 2,000): when the cap is reached, entries older than the tenant's `retentionDays` are rotated out and the tenant's hash chain is relinked to genesis — `previousHash`/`entryHash` are recomputed and `entryCount`/`headHash` updated, so a subsequent `verifyTenant` still passes. Rotation is bounded and never silent at the cap: if the store cannot be brought under `MAX_ENTRIES`, the append is rejected with an explicit retention-review error.
|
|
27
|
+
- Rotation is per-tenant and opt-in: a tenant without a `retentionDays` policy is never rotated (its chain remains strictly append-only), and a tenant under `setLegalHold(true)` is never rotated.
|
|
28
|
+
- `setLegalHold(true)` records an active local hold and blocks `requestDeletion()`.
|
|
29
|
+
- `requestDeletion()` records a request timestamp after the hold check. It does not erase entries, backups, or external copies and does not claim GDPR, SEC, HIPAA, or any other compliance behavior.
|
|
30
|
+
- A real retention/deletion workflow needs an approved retention schedule, backup lifecycle, legal authority, trusted identity, durable external evidence, and a cryptographically preserved anchor before destructive deletion can be designed.
|
|
31
|
+
|
|
32
|
+
## Claimed Basis And Verification
|
|
33
|
+
|
|
34
|
+
- `policy_decision` and `approval` stages echo caller-supplied decisions as `basis: "caller_claimed"` — they record what the caller asserted at admission time, not an independently verified policy/approval decision, and consumers must treat them as claims.
|
|
35
|
+
- `verifyTenant()` returns `tracked: false` with the tenant's genesis hash as head for a tenant that has no entries, and `tracked: true` for a tenant with entries, so "no ledger yet" is distinguishable from a broken or tampered chain.
|
|
36
|
+
|
|
37
|
+
## Trust Boundaries And Limits
|
|
38
|
+
|
|
39
|
+
- `LedgerAccessAuthorizer` is injected. The default authorizer denies everything. Test capability helpers are only local test utilities, not authentication or tenant isolation for a deployed service.
|
|
40
|
+
- Tenant isolation applies to calls that go through a correct injected authorizer. A malicious same-user actor who can replace the local state file and runtime is outside this local filesystem model.
|
|
41
|
+
- The chain is tamper-evident, not absolutely immutable. It does not defend against a compromised host, altered application code, deleted backups, an attacker who replaces both data and trusted head/anchor, distributed filesystems, or a dishonest clock.
|
|
42
|
+
- Sanitization is structural and pattern-based. Operators must inspect incident fixtures before sharing them; GhostAPI does not guarantee perfect anonymization.
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
# Local Approval Inbox Threat Model
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
The approval inbox is a local typed API for the existing `ghostapi-synthetic` action adapter. It does not enable production providers, credentials, deployments, money movement, email, Slack, webhooks, browser approval links, or external notifications.
|
|
6
|
-
|
|
7
|
-
An approval request is derived from a strict action envelope and its canonical SHA-256 hash. The action's risk is derived by the inbox taxonomy, never accepted from the agent as mutable input. The current synthetic operation maps to `update`; the taxonomy also reserves `read`, `create`, `communicate`, `money_movement`, `delete`, `permission_change`, and `deployment` for future reviewed action contracts.
|
|
8
|
-
|
|
9
|
-
## Policy And Display
|
|
10
|
-
|
|
11
|
-
An approval policy can restrict environment, actor, resource, amount, confidence, and action velocity. It defines an expiry and escalation timeout. A request exposes its normalized arguments, exact target, expected effects, reversibility, amount availability/value, policy reason, evidence hash, and successful synthetic preflight result. Missing amount evidence fails a policy that sets a maximum amount.
|
|
12
|
-
|
|
13
|
-
## Approval Invariants
|
|
14
|
-
|
|
15
|
-
- Requests, decisions, artifacts, and audit records are strict schema-v1 local data under `.ghostapi/approvals.json`.
|
|
16
|
-
- Approver identities come from an injected verifier and include a verified stable `principalId`. Unverified caller-shaped objects fail closed.
|
|
17
|
-
- An action actor/workload cannot approve its own action through its approver ID, verified principal ID, or independence key.
|
|
18
|
-
- Critical risks or low confidence require distinct verified principals and `independenceKey` values; aliases cannot satisfy two-person approval.
|
|
19
|
-
- Approval artifacts are action-hash-bound, one-time, expiring, and carry Ed25519 provenance from a durable approval-authority key. They are consumed under the inbox lock before execution starts; resumption never issues or consumes a second artifact.
|
|
20
|
-
- The gateway verifies the signature at submission and again from the persisted record at execution. Inbox artifacts also require verifier-confirmed durable request state with the same request ID, action hash, artifact, and `consumedAt`; the request must be `executing`, or already `executed` with a linked receipt hash. Returning an already completed result additionally requires the inbox's stored receipt hash to match the gateway's durable verified receipt. A gateway configured with only the signing authority's public key cannot execute an inbox artifact.
|
|
21
|
-
- Rejection, revoke, timeout, expiry, policy drift, changed action, or changed execution identity deny execution.
|
|
22
|
-
- Edit-and-resubmit supersedes the prior request and requires a changed canonical action hash.
|
|
23
|
-
- The inbox rechecks the policy at execution and then delegates only to the existing action gateway, which repeats provenance/action/approval/policy/identity/idempotency checks before its synthetic side effect.
|
|
24
|
-
- Every approval transition and verified action receipt are connected through one local SHA-256 audit chain. Local chains are tamper-evident only under the existing filesystem trust model.
|
|
25
|
-
|
|
26
|
-
## Race And Recovery
|
|
27
|
-
|
|
28
|
-
The inbox serializes approval state and artifact consumption with one private file lock. A revoke that acquires the lock first prevents the side effect; an execution that has consumed the artifact first cannot be revoked as if it were still pending. If the process stops after durable `consumedAt`/`executing` state, recovery resubmits the identical signed artifact and delegates to the gateway's receipt chain. A `requested` receipt continues normally only while the action and approval remain valid; an `attempted` or `committed` receipt can be reconciled after expiry because no new attempt is permitted, and a `verified` receipt is returned without another side effect. The inbox changes to `executed` only after linking that verified receipt hash into its audit chain. Repeated recovery and calls after completion return the same verified receipt. A durable gateway `failed` receipt makes the inbox terminally `execution_failed`; an absent receipt or ambiguous attempted outcome remains `executing` and fail-closed rather than being replayed. Artifact data, local hashes, and filesystem write access are not sufficient to mint new valid approvals without the private signing key. Key rotation is explicit through trusted key IDs; unavailable or unknown verifiers deny recovery and execution.
|
|
29
|
-
|
|
30
|
-
## Remaining Limits
|
|
31
|
-
|
|
32
|
-
- The inbox is an API, not a hosted UI or notification channel. Slack/email text must never become an approval source of truth.
|
|
33
|
-
- Signing keys are injected; GhostAPI does not generate, escrow, rotate, or recover durable production key material. Operators must keep private keys outside the data directory and distribute only trusted public keys to executors.
|
|
34
|
-
- There is no authentication transport, RBAC service, trusted OIDC integration, external immutable audit sink, real clock authority, policy engine for production action classes, or real provider executor.
|
|
35
|
-
- A future production integration requires an independently deployed identity/approval authority, provider-specific impact schema, policy authorization, credential broker, kill switch, budgets, durable audit evidence, timeout reconciliation, and compensation semantics.
|
|
1
|
+
# Local Approval Inbox Threat Model
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
The approval inbox is a local typed API for the existing `ghostapi-synthetic` action adapter. It does not enable production providers, credentials, deployments, money movement, email, Slack, webhooks, browser approval links, or external notifications.
|
|
6
|
+
|
|
7
|
+
An approval request is derived from a strict action envelope and its canonical SHA-256 hash. The action's risk is derived by the inbox taxonomy, never accepted from the agent as mutable input. The current synthetic operation maps to `update`; the taxonomy also reserves `read`, `create`, `communicate`, `money_movement`, `delete`, `permission_change`, and `deployment` for future reviewed action contracts.
|
|
8
|
+
|
|
9
|
+
## Policy And Display
|
|
10
|
+
|
|
11
|
+
An approval policy can restrict environment, actor, resource, amount, confidence, and action velocity. It defines an expiry and escalation timeout. A request exposes its normalized arguments, exact target, expected effects, reversibility, amount availability/value, policy reason, evidence hash, and successful synthetic preflight result. Missing amount evidence fails a policy that sets a maximum amount.
|
|
12
|
+
|
|
13
|
+
## Approval Invariants
|
|
14
|
+
|
|
15
|
+
- Requests, decisions, artifacts, and audit records are strict schema-v1 local data under `.ghostapi/approvals.json`.
|
|
16
|
+
- Approver identities come from an injected verifier and include a verified stable `principalId`. Unverified caller-shaped objects fail closed.
|
|
17
|
+
- An action actor/workload cannot approve its own action through its approver ID, verified principal ID, or independence key.
|
|
18
|
+
- Critical risks or low confidence require distinct verified principals and `independenceKey` values; aliases cannot satisfy two-person approval.
|
|
19
|
+
- Approval artifacts are action-hash-bound, one-time, expiring, and carry Ed25519 provenance from a durable approval-authority key. They are consumed under the inbox lock before execution starts; resumption never issues or consumes a second artifact.
|
|
20
|
+
- The gateway verifies the signature at submission and again from the persisted record at execution. Inbox artifacts also require verifier-confirmed durable request state with the same request ID, action hash, artifact, and `consumedAt`; the request must be `executing`, or already `executed` with a linked receipt hash. Returning an already completed result additionally requires the inbox's stored receipt hash to match the gateway's durable verified receipt. A gateway configured with only the signing authority's public key cannot execute an inbox artifact.
|
|
21
|
+
- Rejection, revoke, timeout, expiry, policy drift, changed action, or changed execution identity deny execution.
|
|
22
|
+
- Edit-and-resubmit supersedes the prior request and requires a changed canonical action hash.
|
|
23
|
+
- The inbox rechecks the policy at execution and then delegates only to the existing action gateway, which repeats provenance/action/approval/policy/identity/idempotency checks before its synthetic side effect.
|
|
24
|
+
- Every approval transition and verified action receipt are connected through one local SHA-256 audit chain. Local chains are tamper-evident only under the existing filesystem trust model.
|
|
25
|
+
|
|
26
|
+
## Race And Recovery
|
|
27
|
+
|
|
28
|
+
The inbox serializes approval state and artifact consumption with one private file lock. A revoke that acquires the lock first prevents the side effect; an execution that has consumed the artifact first cannot be revoked as if it were still pending. If the process stops after durable `consumedAt`/`executing` state, recovery resubmits the identical signed artifact and delegates to the gateway's receipt chain. A `requested` receipt continues normally only while the action and approval remain valid; an `attempted` or `committed` receipt can be reconciled after expiry because no new attempt is permitted, and a `verified` receipt is returned without another side effect. The inbox changes to `executed` only after linking that verified receipt hash into its audit chain. Repeated recovery and calls after completion return the same verified receipt. A durable gateway `failed` receipt makes the inbox terminally `execution_failed`; an absent receipt or ambiguous attempted outcome remains `executing` and fail-closed rather than being replayed. Artifact data, local hashes, and filesystem write access are not sufficient to mint new valid approvals without the private signing key. Key rotation is explicit through trusted key IDs; unavailable or unknown verifiers deny recovery and execution.
|
|
29
|
+
|
|
30
|
+
## Remaining Limits
|
|
31
|
+
|
|
32
|
+
- The inbox is an API, not a hosted UI or notification channel. Slack/email text must never become an approval source of truth.
|
|
33
|
+
- Signing keys are injected; GhostAPI does not generate, escrow, rotate, or recover durable production key material. Operators must keep private keys outside the data directory and distribute only trusted public keys to executors.
|
|
34
|
+
- There is no authentication transport, RBAC service, trusted OIDC integration, external immutable audit sink, real clock authority, policy engine for production action classes, or real provider executor.
|
|
35
|
+
- A future production integration requires an independently deployed identity/approval authority, provider-specific impact schema, policy authorization, credential broker, kill switch, budgets, durable audit evidence, timeout reconciliation, and compensation semantics.
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
# Credential Broker And Workload Identity Threat Model
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
The credential broker is a local typed library for a future execution gateway. It does not expose a CLI, MCP tool, HTTP endpoint, environment-variable loader, provider SDK, or credential-return API. The agent/workload never receives upstream secret material through arguments, stdin, environment variables, logs, reports, grants, receipts, or persisted broker metadata.
|
|
6
|
-
|
|
7
|
-
Only server-side execution can read a secret. A caller presents a verified workload identity, a short-lived grant, and an exact action reference. The broker reads secret bytes from an injected vault boundary, passes them directly to an injected server-side executor, then zeroes the temporary byte buffer in a `finally` block. It returns a receipt, never the secret or a bearer token.
|
|
8
|
-
|
|
9
|
-
The included `test-memory-vault`, test executor, workload verifier, action-receipt verifier, and break-glass authorizer exist only for automated tests. They have no network, provider, environment-secret, account, or production side-effect capability. A real integration must supply an existing reviewed vault/KMS adapter and a separately reviewed provider executor; GhostAPI does not implement encryption, key wrapping, or a provider credential protocol.
|
|
10
|
-
|
|
11
|
-
## Secret Lifecycle
|
|
12
|
-
|
|
13
|
-
1. Provisioning: an operator registers non-secret metadata: tenant, project, environment, provider, owner workload binding, scope allowlist, expiry, and opaque vault reference. The vault owns secret creation and storage.
|
|
14
|
-
2. Storage: GhostAPI stores only metadata, grant metadata, and use receipts in `.ghostapi/credential-broker.json`. It rejects unknown fields, symlinks, oversized state, secret-shaped identifiers, and plaintext secret fields. A vault reference is not secret material and must not encode a secret.
|
|
15
|
-
3. Use: an authenticated workload requests a server-only grant for one exact action ID, action hash, and verified action receipt hash. The broker persists `executing` before vault/provider I/O, then rechecks workload, tenant/project/environment, provider, scopes, credential status, grant status, expiry, and action reference immediately before vault access and through an executor-provided guard immediately before its side effect.
|
|
16
|
-
4. Rotation: rotation replaces the opaque vault reference, increments the credential version, and revokes every outstanding grant. It does not touch local synthetic worlds, so local simulation stays available.
|
|
17
|
-
5. Revocation: credential revocation marks the credential and all active grants revoked without waiting for vault/provider I/O. New execution attempts and an executor's final active check are denied before a later side effect.
|
|
18
|
-
6. Audit: broker state records action-linked grant metadata and bounded execution receipts. It never stores the secret, a raw provider request, or an executor response body.
|
|
19
|
-
7. Recovery: failures before the provider executor begins receive `failed`; any executor error receives `unknown` because a side effect may already have happened. Neither is retried automatically. Provider-specific reconciliation and duplicate-side-effect handling remain required before a real executor is enabled.
|
|
20
|
-
|
|
21
|
-
## Workload Identity
|
|
22
|
-
|
|
23
|
-
Schema-v1 workload identities distinguish `agent_run`, `ci_job`, and `production_service`. Each identity binds tenant, project, environment, workload ID, subject ID, run ID, issue time, and expiry. The broker accepts an identity only through an injected verifier; unverified caller-shaped objects fail closed.
|
|
24
|
-
|
|
25
|
-
The identity verifier can additionally report whether an owner workload remains active. `listOrphanedCredentials()` returns non-revoked credentials whose owner workload binding is no longer active, so an operator can revoke or rotate them. It does not automatically broaden, transfer, or delete access.
|
|
26
|
-
|
|
27
|
-
## Invariants
|
|
28
|
-
|
|
29
|
-
- The grant audience is always `ghostapi-server`; no grant is valid for an agent process.
|
|
30
|
-
- A grant is bounded to one tenant, project, environment, workload kind/ID, provider, sorted scope list, credential version, TTL, and exact action receipt.
|
|
31
|
-
- Standard grants last at most 15 minutes. Break-glass grants require an independent trusted authorizer and last at most 5 minutes.
|
|
32
|
-
- Credential metadata and secret material are separate interfaces. Metadata cannot reconstruct the upstream value.
|
|
33
|
-
- Broker and executor both enforce scope. The executor rejects unsupported scope even if a caller somehow reaches it after broker validation.
|
|
34
|
-
- The executor must call its supplied `assertActive()` immediately before its provider side effect; a future adapter that cannot honor this contract is unsupported.
|
|
35
|
-
- A rotated credential invalidates old grants through both revocation and version mismatch. A revoked or expired grant is rejected even when an old request is replayed.
|
|
36
|
-
- Cross-tenant, project, environment, workload, scope, audience, action, and receipt mismatch all fail closed before secret access.
|
|
37
|
-
- A provider executor must create an action-linked receipt. The current test executor has no real provider capability.
|
|
38
|
-
|
|
39
|
-
## Break-Glass
|
|
40
|
-
|
|
41
|
-
Break-glass is disabled by default. An implementation must use a trusted human-controlled approval system that validates a short-lived structured approval bound to the exact action ID/hash/receipt. The approver cannot equal the workload subject or workload ID. The broker stores only approval ID, approver ID, and bounded reason in the grant; it does not store an approval token.
|
|
42
|
-
|
|
43
|
-
## Crash And Memory Limits
|
|
44
|
-
|
|
45
|
-
Node.js does not offer a universal guarantee that secret bytes are absent from every process snapshot, heap copy, debugger, or OS crash dump. The broker minimizes exposure by avoiding strings, logs, environment variables, arguments, persistence, and return values; it uses a temporary `Uint8Array` and clears that buffer after executor completion or failure. Operators must still disable or protect crash/core dumps, debugger attachments, and untrusted process inspection in any real deployment.
|
|
46
|
-
|
|
47
|
-
## Remaining Limits
|
|
48
|
-
|
|
49
|
-
- This is not a production vault, KMS, HSM, hosted identity provider, approval inbox, provider client, or production action gateway.
|
|
50
|
-
- Local JSON storage is coordination and tamper detection only under the existing single-user filesystem trust model; it is not immutable audit storage.
|
|
51
|
-
- Revocation can stop execution before the executor's final active check, but it cannot undo a provider side effect that already crossed that check; a real provider integration still needs provider idempotency and reconciliation.
|
|
52
|
-
- A real provider executor needs its own test-account gate, provider idempotency/reconciliation proof, action-level policy decision, kill switch, budgets/velocity controls, durable audit sink, timeout ambiguity handling, and compensation semantics before any real side effect is enabled.
|
|
1
|
+
# Credential Broker And Workload Identity Threat Model
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
The credential broker is a local typed library for a future execution gateway. It does not expose a CLI, MCP tool, HTTP endpoint, environment-variable loader, provider SDK, or credential-return API. The agent/workload never receives upstream secret material through arguments, stdin, environment variables, logs, reports, grants, receipts, or persisted broker metadata.
|
|
6
|
+
|
|
7
|
+
Only server-side execution can read a secret. A caller presents a verified workload identity, a short-lived grant, and an exact action reference. The broker reads secret bytes from an injected vault boundary, passes them directly to an injected server-side executor, then zeroes the temporary byte buffer in a `finally` block. It returns a receipt, never the secret or a bearer token.
|
|
8
|
+
|
|
9
|
+
The included `test-memory-vault`, test executor, workload verifier, action-receipt verifier, and break-glass authorizer exist only for automated tests. They have no network, provider, environment-secret, account, or production side-effect capability. A real integration must supply an existing reviewed vault/KMS adapter and a separately reviewed provider executor; GhostAPI does not implement encryption, key wrapping, or a provider credential protocol.
|
|
10
|
+
|
|
11
|
+
## Secret Lifecycle
|
|
12
|
+
|
|
13
|
+
1. Provisioning: an operator registers non-secret metadata: tenant, project, environment, provider, owner workload binding, scope allowlist, expiry, and opaque vault reference. The vault owns secret creation and storage.
|
|
14
|
+
2. Storage: GhostAPI stores only metadata, grant metadata, and use receipts in `.ghostapi/credential-broker.json`. It rejects unknown fields, symlinks, oversized state, secret-shaped identifiers, and plaintext secret fields. A vault reference is not secret material and must not encode a secret.
|
|
15
|
+
3. Use: an authenticated workload requests a server-only grant for one exact action ID, action hash, and verified action receipt hash. The broker persists `executing` before vault/provider I/O, then rechecks workload, tenant/project/environment, provider, scopes, credential status, grant status, expiry, and action reference immediately before vault access and through an executor-provided guard immediately before its side effect.
|
|
16
|
+
4. Rotation: rotation replaces the opaque vault reference, increments the credential version, and revokes every outstanding grant. It does not touch local synthetic worlds, so local simulation stays available.
|
|
17
|
+
5. Revocation: credential revocation marks the credential and all active grants revoked without waiting for vault/provider I/O. New execution attempts and an executor's final active check are denied before a later side effect.
|
|
18
|
+
6. Audit: broker state records action-linked grant metadata and bounded execution receipts. It never stores the secret, a raw provider request, or an executor response body.
|
|
19
|
+
7. Recovery: failures before the provider executor begins receive `failed`; any executor error receives `unknown` because a side effect may already have happened. Neither is retried automatically. Provider-specific reconciliation and duplicate-side-effect handling remain required before a real executor is enabled.
|
|
20
|
+
|
|
21
|
+
## Workload Identity
|
|
22
|
+
|
|
23
|
+
Schema-v1 workload identities distinguish `agent_run`, `ci_job`, and `production_service`. Each identity binds tenant, project, environment, workload ID, subject ID, run ID, issue time, and expiry. The broker accepts an identity only through an injected verifier; unverified caller-shaped objects fail closed.
|
|
24
|
+
|
|
25
|
+
The identity verifier can additionally report whether an owner workload remains active. `listOrphanedCredentials()` returns non-revoked credentials whose owner workload binding is no longer active, so an operator can revoke or rotate them. It does not automatically broaden, transfer, or delete access.
|
|
26
|
+
|
|
27
|
+
## Invariants
|
|
28
|
+
|
|
29
|
+
- The grant audience is always `ghostapi-server`; no grant is valid for an agent process.
|
|
30
|
+
- A grant is bounded to one tenant, project, environment, workload kind/ID, provider, sorted scope list, credential version, TTL, and exact action receipt.
|
|
31
|
+
- Standard grants last at most 15 minutes. Break-glass grants require an independent trusted authorizer and last at most 5 minutes.
|
|
32
|
+
- Credential metadata and secret material are separate interfaces. Metadata cannot reconstruct the upstream value.
|
|
33
|
+
- Broker and executor both enforce scope. The executor rejects unsupported scope even if a caller somehow reaches it after broker validation.
|
|
34
|
+
- The executor must call its supplied `assertActive()` immediately before its provider side effect; a future adapter that cannot honor this contract is unsupported.
|
|
35
|
+
- A rotated credential invalidates old grants through both revocation and version mismatch. A revoked or expired grant is rejected even when an old request is replayed.
|
|
36
|
+
- Cross-tenant, project, environment, workload, scope, audience, action, and receipt mismatch all fail closed before secret access.
|
|
37
|
+
- A provider executor must create an action-linked receipt. The current test executor has no real provider capability.
|
|
38
|
+
|
|
39
|
+
## Break-Glass
|
|
40
|
+
|
|
41
|
+
Break-glass is disabled by default. An implementation must use a trusted human-controlled approval system that validates a short-lived structured approval bound to the exact action ID/hash/receipt. The approver cannot equal the workload subject or workload ID. The broker stores only approval ID, approver ID, and bounded reason in the grant; it does not store an approval token.
|
|
42
|
+
|
|
43
|
+
## Crash And Memory Limits
|
|
44
|
+
|
|
45
|
+
Node.js does not offer a universal guarantee that secret bytes are absent from every process snapshot, heap copy, debugger, or OS crash dump. The broker minimizes exposure by avoiding strings, logs, environment variables, arguments, persistence, and return values; it uses a temporary `Uint8Array` and clears that buffer after executor completion or failure. Operators must still disable or protect crash/core dumps, debugger attachments, and untrusted process inspection in any real deployment.
|
|
46
|
+
|
|
47
|
+
## Remaining Limits
|
|
48
|
+
|
|
49
|
+
- This is not a production vault, KMS, HSM, hosted identity provider, approval inbox, provider client, or production action gateway.
|
|
50
|
+
- Local JSON storage is coordination and tamper detection only under the existing single-user filesystem trust model; it is not immutable audit storage.
|
|
51
|
+
- Revocation can stop execution before the executor's final active check, but it cannot undo a provider side effect that already crossed that check; a real provider integration still needs provider idempotency and reconciliation.
|
|
52
|
+
- A real provider executor needs its own test-account gate, provider idempotency/reconciliation proof, action-level policy decision, kill switch, budgets/velocity controls, durable audit sink, timeout ambiguity handling, and compensation semantics before any real side effect is enabled.
|