@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,111 +1,111 @@
|
|
|
1
|
-
# Reliability Surface Threat Model
|
|
2
|
-
|
|
3
|
-
Applies to the local reliability layer: SLO controller, reconciliation service, cost governance, runtime health, and backup/restore.
|
|
4
|
-
|
|
5
|
-
## Scope
|
|
6
|
-
|
|
7
|
-
This threat model covers the reliability module added in the "reliability" session:
|
|
8
|
-
|
|
9
|
-
- `slo.json`, `reconciliation.json`, `costs.json` local persisted stores under `.ghostapi/reliability/`.
|
|
10
|
-
- Backup and restore of the whole local data directory, including the reliability stores.
|
|
11
|
-
- `/health` and `/health/readiness` HTTP endpoints backed by `checkRuntimeHealth`.
|
|
12
|
-
- Reconciliation reading the action ledger and the synthetic worlds directory.
|
|
13
|
-
|
|
14
|
-
`checkRuntimeHealth` treats every canonical store as a first-class dependency, including `inventory.json` (`inventoryStore`), so a corrupt or missing inventory store is reported as `degraded` and flips readiness, not just the reliability stores.
|
|
15
|
-
|
|
16
|
-
The reliability layer adds no provider, credential, network egress, or hosted control-plane surface. All of it is local-first and synthetic.
|
|
17
|
-
|
|
18
|
-
## Trust Boundaries
|
|
19
|
-
|
|
20
|
-
| Boundary
|
|
21
|
-
|
|
|
22
|
-
| Operator identity | SLO, reconciliation, and cost operators authenticate through injectable authorizers; the test authorizer binds issued identities by reference | Real authn/authz infrastructure
|
|
23
|
-
| Ledger access
|
|
24
|
-
| Provider state
|
|
25
|
-
| HTTP surface
|
|
26
|
-
|
|
27
|
-
## Assets
|
|
28
|
-
|
|
29
|
-
- SLO samples and configured targets (`slo.json`).
|
|
30
|
-
- Reconciliation findings, resolutions, and last-run state (`reconciliation.json`).
|
|
31
|
-
- Cost records, budgets, alerts (`costs.json`).
|
|
32
|
-
- Backup manifest and copies (`reliability/backups/`).
|
|
33
|
-
- The runtime health report (derived, not persisted).
|
|
34
|
-
|
|
35
|
-
## Threats And Mitigations
|
|
36
|
-
|
|
37
|
-
### T1. Unauthorized SLO recording poisons availability targets
|
|
38
|
-
|
|
39
|
-
`recordSample`/`recordSamples` accept a capability object instead of an operator identity. The capability must be a member of the record-capability set created by `createSloRecordIdentity`; any other object is rejected with "record capability". This is reference-bound, so ambient objects cannot be forged.
|
|
40
|
-
|
|
41
|
-
Samples are bounded: `MAX_SAMPLES_PER_METRIC` (5,000), `MAX_SAMPLES` (10,000) globally, enforced on every mutation, and `recordSamples` caps each call at `MAX_RECORD_BATCH` (1,000) so a single oversized call cannot blow past the store bound. SLO store bytes are capped at 4 MiB.
|
|
42
|
-
|
|
43
|
-
Latency evaluation only counts samples whose `ok` flag is true; a latency breach requires both `sample.ok === true` and `durationMs` above the target. Failed samples can no longer be counted as "within SLO" by reporting a low duration.
|
|
44
|
-
|
|
45
|
-
### T2. Operator impersonation on configure/evaluate/inspect
|
|
46
|
-
|
|
47
|
-
Every SLO operator action authenticates through the configured authorizer and validates permissions against `slo.configure`/`slo.inspect` only. Identities are reference-bound objects issued by the authorizer; a plain `{}` or any other object is rejected as "not authenticated".
|
|
48
|
-
|
|
49
|
-
### T3. Reconciliation reads a tampered ledger
|
|
50
|
-
|
|
51
|
-
`runReconciliation` requires the operator to hold the `reconciliation.manage` permission and takes an explicit `{ identity }` input; a read-only operator is rejected. It calls `exportTenant`; if ledger integrity verification fails, reconciliation is blocked with a clear error and no findings or SLO samples are written. A tampered ledger cannot silently produce a "valid" report. Provider read failures are detected structurally (`SyntheticWorldError` with code `WORLD_NOT_FOUND`) rather than by matching error text, so a missing world is reported deterministically.
|
|
52
|
-
|
|
53
|
-
### T4. Reconciliation leaks or records sensitive provider evidence
|
|
54
|
-
|
|
55
|
-
Provider receipts are reduced to `{ actionId }` for matching, and worlds are inspected through the same receipts shape. Findings carry only `actionHash` and bounded non-secret `detail`/`evidenceRef` strings (validated by `identifier`/`hash`/`evidence`/`text`, which reject control characters and secret-shaped values via `sanitizeSecretString`).
|
|
56
|
-
|
|
57
|
-
### T5. Cost store is poisoned or exploded
|
|
58
|
-
|
|
59
|
-
Cost records are capped (`MAX_RECORDS` 10,000), budgets capped (`MAX_BUDGETS` 32), alerts capped (`MAX_ALERTS` 100), window capped (`MAX_WINDOW_MS` 90 days), store bytes capped at 4 MiB. Amounts are non-negative integers. `recordCost` is idempotent per tenant: a duplicate `actionId` for the same tenant is rejected, so a replay of a cost record cannot double-charge a budget. `report()` is a pure read — it never writes alert state; only `listAlerts()` persists derived alerts. Reports and alerts are scoped to the operator's tenant via the optional `CostOperator.tenantId`, and alerts honor each budget's `alertOnExceed` flag, so an explicit opt-out cannot be overridden by a global alert pass. Forecast output is explicitly labeled as a linear extrapolation approximation, not a provider invoice.
|
|
60
|
-
|
|
61
|
-
### T6. Backup/restore path traversal
|
|
62
|
-
|
|
63
|
-
Restore validates every manifest entry path with `normalizeEntryPath` (rejects `..`, absolute paths, drive-letter prefixes, NUL bytes) and `assertContained` bounds every source and target path within its root. A crafted manifest that escapes the backup root is rejected before any file is written.
|
|
64
|
-
|
|
65
|
-
### T7. Tampered backup restores bad data
|
|
66
|
-
|
|
67
|
-
Restore requires `manifest.verified === true` and re-verifies sha256 and size of every entry before and after copy, plus JSON structure for `.json` entries. Tampering with any backed-up file fails "integrity verification" and aborts the restore.
|
|
68
|
-
|
|
69
|
-
### T8. Backup exfiltrates or follows unsafe links
|
|
70
|
-
|
|
71
|
-
`collectBackupFiles` refuses symbolic links, non-regular files, `.lock`/`.tmp` files, and refuses the whole backup if any is encountered. Exclusions are path-based, not name-based: only the canonical `cache` and `backups` directories, the current destination, and a top-level `runs` directory are skipped — a nested directory merely named `cache` or `backups` inside a world/contract is still backed up. Because the canonical backups location is excluded, backups do not recursively include earlier backups.
|
|
72
|
-
|
|
73
|
-
### T9. Runtime health check is a denial vector
|
|
74
|
-
|
|
75
|
-
Store files are read with `MAX_CHECK_FILE_BYTES` (4 MiB) cap; oversized or non-JSON stores are reported as `degraded`, never loaded fully. The `/health` endpoint returns only `{ ok, ready }`; `/health/readiness` returns the structural report and 503 when not ready.
|
|
76
|
-
|
|
77
|
-
### T10. Backup/restore destroys the source
|
|
78
|
-
|
|
79
|
-
Backup only reads the source; restore refuses a target that is the source or inside it, and refuses to restore into a non-empty target directory, so an existing data directory cannot be silently overwritten. Copy is byte-verified before the atomic write to the destination, and failed copies clean up the partial destination.
|
|
80
|
-
|
|
81
|
-
## Permissions And Capabilities Summary
|
|
82
|
-
|
|
83
|
-
| Action
|
|
84
|
-
|
|
|
85
|
-
| SLO record
|
|
86
|
-
| SLO configure/inspect/evaluate
|
|
87
|
-
| Reconciliation run
|
|
88
|
-
| Reconciliation findings/resolve
|
|
89
|
-
| Cost record/configure/report/alerts | operator authorizer + `cost.*` permissions
|
|
90
|
-
| Health/backup/restore
|
|
91
|
-
|
|
92
|
-
## Limits
|
|
93
|
-
|
|
94
|
-
| Resource
|
|
95
|
-
|
|
|
96
|
-
| SLO samples per metric
|
|
97
|
-
| SLO samples total
|
|
98
|
-
| SLO targets
|
|
99
|
-
| SLO window
|
|
100
|
-
| Reconciliation findings
|
|
101
|
-
| Cost records / budgets / alerts | 10,000 / 32 / 100 |
|
|
102
|
-
| Cost window
|
|
103
|
-
| Store bytes
|
|
104
|
-
| Backup total bytes
|
|
105
|
-
| Health check file bytes
|
|
106
|
-
|
|
107
|
-
## Out Of Scope
|
|
108
|
-
|
|
109
|
-
- Live SLO alerting to external systems (no egress was added).
|
|
110
|
-
- Multi-node reconciliation consensus (local single-process semantics).
|
|
111
|
-
- Backup to remote/object storage (local directory only).
|
|
1
|
+
# Reliability Surface Threat Model
|
|
2
|
+
|
|
3
|
+
Applies to the local reliability layer: SLO controller, reconciliation service, cost governance, runtime health, and backup/restore.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
This threat model covers the reliability module added in the "reliability" session:
|
|
8
|
+
|
|
9
|
+
- `slo.json`, `reconciliation.json`, `costs.json` local persisted stores under `.ghostapi/reliability/`.
|
|
10
|
+
- Backup and restore of the whole local data directory, including the reliability stores.
|
|
11
|
+
- `/health` and `/health/readiness` HTTP endpoints backed by `checkRuntimeHealth`.
|
|
12
|
+
- Reconciliation reading the action ledger and the synthetic worlds directory.
|
|
13
|
+
|
|
14
|
+
`checkRuntimeHealth` treats every canonical store as a first-class dependency, including `inventory.json` (`inventoryStore`), so a corrupt or missing inventory store is reported as `degraded` and flips readiness, not just the reliability stores.
|
|
15
|
+
|
|
16
|
+
The reliability layer adds no provider, credential, network egress, or hosted control-plane surface. All of it is local-first and synthetic.
|
|
17
|
+
|
|
18
|
+
## Trust Boundaries
|
|
19
|
+
|
|
20
|
+
| Boundary | In scope | Out of scope |
|
|
21
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
|
|
22
|
+
| Operator identity | SLO, reconciliation, and cost operators authenticate through injectable authorizers; the test authorizer binds issued identities by reference | Real authn/authz infrastructure |
|
|
23
|
+
| Ledger access | Reconciliation uses a verified ledger capability (reference-bound, tenant-scoped, permission-checked) | Key management for live providers |
|
|
24
|
+
| Provider state | Reconciliation inspects synthetic worlds through `createWorldStateReconciliationProvider` | Live provider APIs |
|
|
25
|
+
| HTTP surface | `/health`, `/health/readiness` are public but return only structural readiness | Authenticated control APIs |
|
|
26
|
+
|
|
27
|
+
## Assets
|
|
28
|
+
|
|
29
|
+
- SLO samples and configured targets (`slo.json`).
|
|
30
|
+
- Reconciliation findings, resolutions, and last-run state (`reconciliation.json`).
|
|
31
|
+
- Cost records, budgets, alerts (`costs.json`).
|
|
32
|
+
- Backup manifest and copies (`reliability/backups/`).
|
|
33
|
+
- The runtime health report (derived, not persisted).
|
|
34
|
+
|
|
35
|
+
## Threats And Mitigations
|
|
36
|
+
|
|
37
|
+
### T1. Unauthorized SLO recording poisons availability targets
|
|
38
|
+
|
|
39
|
+
`recordSample`/`recordSamples` accept a capability object instead of an operator identity. The capability must be a member of the record-capability set created by `createSloRecordIdentity`; any other object is rejected with "record capability". This is reference-bound, so ambient objects cannot be forged.
|
|
40
|
+
|
|
41
|
+
Samples are bounded: `MAX_SAMPLES_PER_METRIC` (5,000), `MAX_SAMPLES` (10,000) globally, enforced on every mutation, and `recordSamples` caps each call at `MAX_RECORD_BATCH` (1,000) so a single oversized call cannot blow past the store bound. SLO store bytes are capped at 4 MiB.
|
|
42
|
+
|
|
43
|
+
Latency evaluation only counts samples whose `ok` flag is true; a latency breach requires both `sample.ok === true` and `durationMs` above the target. Failed samples can no longer be counted as "within SLO" by reporting a low duration.
|
|
44
|
+
|
|
45
|
+
### T2. Operator impersonation on configure/evaluate/inspect
|
|
46
|
+
|
|
47
|
+
Every SLO operator action authenticates through the configured authorizer and validates permissions against `slo.configure`/`slo.inspect` only. Identities are reference-bound objects issued by the authorizer; a plain `{}` or any other object is rejected as "not authenticated".
|
|
48
|
+
|
|
49
|
+
### T3. Reconciliation reads a tampered ledger
|
|
50
|
+
|
|
51
|
+
`runReconciliation` requires the operator to hold the `reconciliation.manage` permission and takes an explicit `{ identity }` input; a read-only operator is rejected. It calls `exportTenant`; if ledger integrity verification fails, reconciliation is blocked with a clear error and no findings or SLO samples are written. A tampered ledger cannot silently produce a "valid" report. Provider read failures are detected structurally (`SyntheticWorldError` with code `WORLD_NOT_FOUND`) rather than by matching error text, so a missing world is reported deterministically.
|
|
52
|
+
|
|
53
|
+
### T4. Reconciliation leaks or records sensitive provider evidence
|
|
54
|
+
|
|
55
|
+
Provider receipts are reduced to `{ actionId }` for matching, and worlds are inspected through the same receipts shape. Findings carry only `actionHash` and bounded non-secret `detail`/`evidenceRef` strings (validated by `identifier`/`hash`/`evidence`/`text`, which reject control characters and secret-shaped values via `sanitizeSecretString`).
|
|
56
|
+
|
|
57
|
+
### T5. Cost store is poisoned or exploded
|
|
58
|
+
|
|
59
|
+
Cost records are capped (`MAX_RECORDS` 10,000), budgets capped (`MAX_BUDGETS` 32), alerts capped (`MAX_ALERTS` 100), window capped (`MAX_WINDOW_MS` 90 days), store bytes capped at 4 MiB. Amounts are non-negative integers. `recordCost` is idempotent per tenant: a duplicate `actionId` for the same tenant is rejected, so a replay of a cost record cannot double-charge a budget. `report()` is a pure read — it never writes alert state; only `listAlerts()` persists derived alerts. Reports and alerts are scoped to the operator's tenant via the optional `CostOperator.tenantId`, and alerts honor each budget's `alertOnExceed` flag, so an explicit opt-out cannot be overridden by a global alert pass. Forecast output is explicitly labeled as a linear extrapolation approximation, not a provider invoice.
|
|
60
|
+
|
|
61
|
+
### T6. Backup/restore path traversal
|
|
62
|
+
|
|
63
|
+
Restore validates every manifest entry path with `normalizeEntryPath` (rejects `..`, absolute paths, drive-letter prefixes, NUL bytes) and `assertContained` bounds every source and target path within its root. A crafted manifest that escapes the backup root is rejected before any file is written.
|
|
64
|
+
|
|
65
|
+
### T7. Tampered backup restores bad data
|
|
66
|
+
|
|
67
|
+
Restore requires `manifest.verified === true` and re-verifies sha256 and size of every entry before and after copy, plus JSON structure for `.json` entries. Tampering with any backed-up file fails "integrity verification" and aborts the restore.
|
|
68
|
+
|
|
69
|
+
### T8. Backup exfiltrates or follows unsafe links
|
|
70
|
+
|
|
71
|
+
`collectBackupFiles` refuses symbolic links, non-regular files, `.lock`/`.tmp` files, and refuses the whole backup if any is encountered. Exclusions are path-based, not name-based: only the canonical `cache` and `backups` directories, the current destination, and a top-level `runs` directory are skipped — a nested directory merely named `cache` or `backups` inside a world/contract is still backed up. Because the canonical backups location is excluded, backups do not recursively include earlier backups.
|
|
72
|
+
|
|
73
|
+
### T9. Runtime health check is a denial vector
|
|
74
|
+
|
|
75
|
+
Store files are read with `MAX_CHECK_FILE_BYTES` (4 MiB) cap; oversized or non-JSON stores are reported as `degraded`, never loaded fully. The `/health` endpoint returns only `{ ok, ready }`; `/health/readiness` returns the structural report and 503 when not ready.
|
|
76
|
+
|
|
77
|
+
### T10. Backup/restore destroys the source
|
|
78
|
+
|
|
79
|
+
Backup only reads the source; restore refuses a target that is the source or inside it, and refuses to restore into a non-empty target directory, so an existing data directory cannot be silently overwritten. Copy is byte-verified before the atomic write to the destination, and failed copies clean up the partial destination.
|
|
80
|
+
|
|
81
|
+
## Permissions And Capabilities Summary
|
|
82
|
+
|
|
83
|
+
| Action | Check |
|
|
84
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
85
|
+
| SLO record | record capability in `sloRecordCapabilities` |
|
|
86
|
+
| SLO configure/inspect/evaluate | operator authorizer + `slo.configure`/`slo.inspect` |
|
|
87
|
+
| Reconciliation run | operator authorizer + `reconciliation.manage` + ledger capability (tenant-scoped, `export`) |
|
|
88
|
+
| Reconciliation findings/resolve | operator authorizer + `reconciliation.inspect`/`reconciliation.manage` |
|
|
89
|
+
| Cost record/configure/report/alerts | operator authorizer + `cost.*` permissions |
|
|
90
|
+
| Health/backup/restore | local-only; backup/restore are not exposed over HTTP |
|
|
91
|
+
|
|
92
|
+
## Limits
|
|
93
|
+
|
|
94
|
+
| Resource | Limit |
|
|
95
|
+
| ------------------------------- | ----------------- |
|
|
96
|
+
| SLO samples per metric | 5,000 |
|
|
97
|
+
| SLO samples total | 10,000 |
|
|
98
|
+
| SLO targets | 32 |
|
|
99
|
+
| SLO window | 1 hour .. 30 days |
|
|
100
|
+
| Reconciliation findings | 1,000 |
|
|
101
|
+
| Cost records / budgets / alerts | 10,000 / 32 / 100 |
|
|
102
|
+
| Cost window | up to 90 days |
|
|
103
|
+
| Store bytes | 4 MiB each |
|
|
104
|
+
| Backup total bytes | 64 MiB |
|
|
105
|
+
| Health check file bytes | 4 MiB |
|
|
106
|
+
|
|
107
|
+
## Out Of Scope
|
|
108
|
+
|
|
109
|
+
- Live SLO alerting to external systems (no egress was added).
|
|
110
|
+
- Multi-node reconciliation consensus (local single-process semantics).
|
|
111
|
+
- Backup to remote/object storage (local directory only).
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
# Local Synthetic Trust Ladder Threat Model
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
|
|
5
|
-
The Session 26 trust ladder is a local, synthetic, data-only preparation layer. It models `simulate`, `shadow`, `dry-run`, `approve`, `bounded-auto`, and `trusted` capability contracts, promotion evidence, canary eligibility, comparisons, rollback reasons, and audit records. It does not execute an action and does not integrate with the action gateway, approval inbox, credential broker, vault, provider SDK/client, external HTTP, provider account, test account, hosted control plane, or notification transport.
|
|
6
|
-
|
|
7
|
-
The local synthetic runtime is not production authorization. `trusted` is intentionally unsupported. `dry-run` is unsupported because no provider-official safe dry-run semantic exists for `ghostapi-synthetic`; it is never emulated by ordinary execution.
|
|
8
|
-
|
|
9
|
-
## Trust Boundaries
|
|
10
|
-
|
|
11
|
-
- Target identities are strict synthetic-only values. Production and test-account identities are rejected rather than mixed into local state.
|
|
12
|
-
- Owner decisions arrive only through an injected verifier and compare the verifier-issued stable `principalId` to policy. Caller-shaped owner objects fail closed.
|
|
13
|
-
- Promotion evidence is bounded metadata: run count, violation/error count, named eval status, and timestamps. LLM confidence is not a signal.
|
|
14
|
-
- Shadow comparisons accept only SHA-256 action/context metadata and return matching evidence. They do not read raw provider inputs or invoke an adapter.
|
|
15
|
-
- Bounded outcome comparisons accept only action/outcome/receipt hashes. They do not perform the bounded execution being assessed.
|
|
16
|
-
- State uses private local storage, regular-file/symlink checks, byte limits, a file lock, atomic replacement, and a bounded SHA-256 audit chain. This is coordination/tamper evidence under the existing local filesystem model, not an immutable audit sink.
|
|
17
|
-
|
|
18
|
-
## Invariants
|
|
19
|
-
|
|
20
|
-
- Every local capability declares `externalSideEffects: false`.
|
|
21
|
-
- `dry-run` and `trusted` are explicitly unsupported; unsupported levels cannot be promoted into.
|
|
22
|
-
- Promotion has no automatic path. It requires the configured verified owner, fresh evidence, minimum runs, every required passing eval, and violation/error rates at or below policy thresholds.
|
|
23
|
-
- Promotion advances only to the next supported level, so an operator cannot skip review stages.
|
|
24
|
-
- Canary assignment is deterministic from a SHA-256 policy/target bucket, checks tenant and resource scope first, and uses a 0-10,000 basis-point percentage.
|
|
25
|
-
- A canary violation can immediately demote the target to `approve` or open the circuit breaker based on policy. Stop conditions open the breaker. Once open, no further assignment, comparison, or canary outcome is accepted.
|
|
26
|
-
- `rollbackToApproval()` requires the verified policy owner and appends an audit record with the supplied bounded reason.
|
|
27
|
-
- The implementation cannot mutate a synthetic world or a provider because it has no execution dependency or capability.
|
|
28
|
-
|
|
29
|
-
## Remaining Limits
|
|
30
|
-
|
|
31
|
-
- Shadow and outcome evidence compare supplied hash metadata. They cannot prove a real provider request or external outcome because the implementation deliberately has no provider transport.
|
|
32
|
-
- This is not an approval authority, action-level policy engine, kill switch for a real provider, budget/velocity enforcement gateway, reconciliation service, test-account boundary, or production audit system.
|
|
33
|
-
- A future real provider integration requires a separately reviewed provider-specific identity model, official dry-run proof where claimed, action authorization, inbox/credential execution boundary, idempotency and reconciliation semantics, kill switch, budgets, durable audit storage, and explicit owner/test-account gates before any side effect is enabled.
|
|
1
|
+
# Local Synthetic Trust Ladder Threat Model
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
The Session 26 trust ladder is a local, synthetic, data-only preparation layer. It models `simulate`, `shadow`, `dry-run`, `approve`, `bounded-auto`, and `trusted` capability contracts, promotion evidence, canary eligibility, comparisons, rollback reasons, and audit records. It does not execute an action and does not integrate with the action gateway, approval inbox, credential broker, vault, provider SDK/client, external HTTP, provider account, test account, hosted control plane, or notification transport.
|
|
6
|
+
|
|
7
|
+
The local synthetic runtime is not production authorization. `trusted` is intentionally unsupported. `dry-run` is unsupported because no provider-official safe dry-run semantic exists for `ghostapi-synthetic`; it is never emulated by ordinary execution.
|
|
8
|
+
|
|
9
|
+
## Trust Boundaries
|
|
10
|
+
|
|
11
|
+
- Target identities are strict synthetic-only values. Production and test-account identities are rejected rather than mixed into local state.
|
|
12
|
+
- Owner decisions arrive only through an injected verifier and compare the verifier-issued stable `principalId` to policy. Caller-shaped owner objects fail closed.
|
|
13
|
+
- Promotion evidence is bounded metadata: run count, violation/error count, named eval status, and timestamps. LLM confidence is not a signal.
|
|
14
|
+
- Shadow comparisons accept only SHA-256 action/context metadata and return matching evidence. They do not read raw provider inputs or invoke an adapter.
|
|
15
|
+
- Bounded outcome comparisons accept only action/outcome/receipt hashes. They do not perform the bounded execution being assessed.
|
|
16
|
+
- State uses private local storage, regular-file/symlink checks, byte limits, a file lock, atomic replacement, and a bounded SHA-256 audit chain. This is coordination/tamper evidence under the existing local filesystem model, not an immutable audit sink.
|
|
17
|
+
|
|
18
|
+
## Invariants
|
|
19
|
+
|
|
20
|
+
- Every local capability declares `externalSideEffects: false`.
|
|
21
|
+
- `dry-run` and `trusted` are explicitly unsupported; unsupported levels cannot be promoted into.
|
|
22
|
+
- Promotion has no automatic path. It requires the configured verified owner, fresh evidence, minimum runs, every required passing eval, and violation/error rates at or below policy thresholds.
|
|
23
|
+
- Promotion advances only to the next supported level, so an operator cannot skip review stages.
|
|
24
|
+
- Canary assignment is deterministic from a SHA-256 policy/target bucket, checks tenant and resource scope first, and uses a 0-10,000 basis-point percentage.
|
|
25
|
+
- A canary violation can immediately demote the target to `approve` or open the circuit breaker based on policy. Stop conditions open the breaker. Once open, no further assignment, comparison, or canary outcome is accepted.
|
|
26
|
+
- `rollbackToApproval()` requires the verified policy owner and appends an audit record with the supplied bounded reason.
|
|
27
|
+
- The implementation cannot mutate a synthetic world or a provider because it has no execution dependency or capability.
|
|
28
|
+
|
|
29
|
+
## Remaining Limits
|
|
30
|
+
|
|
31
|
+
- Shadow and outcome evidence compare supplied hash metadata. They cannot prove a real provider request or external outcome because the implementation deliberately has no provider transport.
|
|
32
|
+
- This is not an approval authority, action-level policy engine, kill switch for a real provider, budget/velocity enforcement gateway, reconciliation service, test-account boundary, or production audit system.
|
|
33
|
+
- A future real provider integration requires a separately reviewed provider-specific identity model, official dry-run proof where claimed, action authorization, inbox/credential execution boundary, idempotency and reconciliation semantics, kill switch, budgets, durable audit storage, and explicit owner/test-account gates before any side effect is enabled.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Local Product Telemetry
|
|
2
|
+
|
|
3
|
+
Product telemetry is disabled by default and has no network transport.
|
|
4
|
+
|
|
5
|
+
When explicitly enabled, GhostAPI stores four aggregate counters and up to eight ISO week labels in `.ghostapi/product-telemetry.json`. It does not record source code, request or response traffic, commands, provider names, repository identity, credentials, or secrets.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ghostapi telemetry enable
|
|
9
|
+
ghostapi telemetry status
|
|
10
|
+
ghostapi telemetry export --json
|
|
11
|
+
ghostapi telemetry disable
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`disable` deletes the local telemetry file. The data is not uploaded by GhostAPI; exporting or sharing it is an operator action.
|