@phosra/cli 0.1.0
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/README.md +42 -0
- package/dist/bin.d.ts +19 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +159 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/caps.d.ts +16 -0
- package/dist/commands/caps.d.ts.map +1 -0
- package/dist/commands/caps.js +125 -0
- package/dist/commands/caps.js.map +1 -0
- package/dist/commands/doctor.d.ts +34 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +321 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/gk-check.d.ts +29 -0
- package/dist/commands/gk-check.d.ts.map +1 -0
- package/dist/commands/gk-check.js +134 -0
- package/dist/commands/gk-check.js.map +1 -0
- package/dist/commands/init.d.ts +18 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +90 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/link-write.d.ts +26 -0
- package/dist/commands/link-write.d.ts.map +1 -0
- package/dist/commands/link-write.js +129 -0
- package/dist/commands/link-write.js.map +1 -0
- package/dist/commands/register.d.ts +63 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +167 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/config.d.ts +72 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +94 -0
- package/dist/config.js.map +1 -0
- package/dist/envelope.d.ts +32 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +53 -0
- package/dist/envelope.js.map +1 -0
- package/dist/keygen.d.ts +29 -0
- package/dist/keygen.d.ts.map +1 -0
- package/dist/keygen.js +38 -0
- package/dist/keygen.js.map +1 -0
- package/dist/out.d.ts +33 -0
- package/dist/out.d.ts.map +1 -0
- package/dist/out.js +76 -0
- package/dist/out.js.map +1 -0
- package/dist/round-trip.d.ts +51 -0
- package/dist/round-trip.d.ts.map +1 -0
- package/dist/round-trip.js +115 -0
- package/dist/round-trip.js.map +1 -0
- package/dist/sender-key.d.ts +26 -0
- package/dist/sender-key.d.ts.map +1 -0
- package/dist/sender-key.js +35 -0
- package/dist/sender-key.js.map +1 -0
- package/dist/transport.d.ts +30 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +62 -0
- package/dist/transport.js.map +1 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# `@phosra/cli`
|
|
2
|
+
|
|
3
|
+
The `phosra` command-line tool — the fastest way to verify a Phosra OCSS integration and prove a signed round-trip against the hosted census, **with zero provisioning**.
|
|
4
|
+
|
|
5
|
+
> **Status:** not yet published to npm. Until then, run from the monorepo (`packages/cli`) after `npm run build`, or contact `developers@phosra.com`. Full guide: **https://docs.phosra.com/integration/cli**
|
|
6
|
+
|
|
7
|
+
## What it does (and doesn't)
|
|
8
|
+
|
|
9
|
+
The CLI is a thin, **§12.3-clean** wrapper over the SDKs (`@openchildsafety/ocss`, `@phosra/link`, `@phosra/gatekeeper`). It **verifies** signed artifacts to the Ed25519 trust root and **drives** the census — it holds **no authority**: it never mints a grant, accepts a rule, publishes the trust list, or carries billing. Keys are generated client-side only. The census is the sole safety authority.
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
phosra init --role provider # scaffold .phosra.env against the shared sandbox DID (zero backend)
|
|
15
|
+
phosra doctor # verify the whole setup end-to-end → a green signed round-trip
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`phosra doctor` runs five ordered, fail-closed checks (honest WARN/SKIP, never a false green):
|
|
19
|
+
|
|
20
|
+
1. `census_reachable` — `/health`
|
|
21
|
+
2. `trust_list_verified` — `/.well-known/ocss/trust-list` verified to root
|
|
22
|
+
3. `caps_verified` — `/.well-known/ocss/capabilities` (the self-describing rule + version doc) verified to root
|
|
23
|
+
4. `version_negotiates` — spec-version range negotiation
|
|
24
|
+
5. `sandbox_round_trip` — a full §8.3.2 consent + §8.3.1 rule write (consent 201 / rule 201)
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
| Command | What it does |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `phosra init --role provider\|platform` | Scaffold a working `.phosra.env` against the shared sandbox |
|
|
31
|
+
| `phosra doctor` | The five end-to-end checks above |
|
|
32
|
+
| `phosra caps` | Fetch + verify + pretty-print the capabilities doc |
|
|
33
|
+
| `phosra link write` | Provider: sign + write a rule (a real census write) |
|
|
34
|
+
| `phosra gatekeeper check` | Platform: verify a profile + evaluate a decision |
|
|
35
|
+
|
|
36
|
+
Every command supports `--json` for CI and agent use.
|
|
37
|
+
|
|
38
|
+
## Configuration
|
|
39
|
+
|
|
40
|
+
Resolution order: environment variable → `.phosra.env` → baked-in sandbox default. Point at a different census with `PHOSRA_CENSUS_URL` + `PHOSRA_TRUST_ROOT_X`.
|
|
41
|
+
|
|
42
|
+
All baked-in keys are **sandbox-only, deterministic test keys** — never production material.
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @phosra/cli — main entry point.
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* phosra init [--role provider|platform] [--force] [--json]
|
|
7
|
+
* phosra doctor [--json]
|
|
8
|
+
* phosra caps [--json]
|
|
9
|
+
*
|
|
10
|
+
* Config priority: process.env > .phosra.env in cwd > baked-in sandbox defaults.
|
|
11
|
+
* The sandbox defaults wire to the STAGING shared sandbox (household-acme,
|
|
12
|
+
* staging census URL, sandbox trust root) — zero provisioning required.
|
|
13
|
+
*
|
|
14
|
+
* §12.3 clean: the CLI VERIFIES and DRIVES the census. It holds NO authority:
|
|
15
|
+
* it cannot mint grants, accept rules on behalf of a child, publish the trust
|
|
16
|
+
* list, or carry billing. The census is the sole safety authority.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=bin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @phosra/cli — main entry point.
|
|
4
|
+
*
|
|
5
|
+
* Commands:
|
|
6
|
+
* phosra init [--role provider|platform] [--force] [--json]
|
|
7
|
+
* phosra doctor [--json]
|
|
8
|
+
* phosra caps [--json]
|
|
9
|
+
*
|
|
10
|
+
* Config priority: process.env > .phosra.env in cwd > baked-in sandbox defaults.
|
|
11
|
+
* The sandbox defaults wire to the STAGING shared sandbox (household-acme,
|
|
12
|
+
* staging census URL, sandbox trust root) — zero provisioning required.
|
|
13
|
+
*
|
|
14
|
+
* §12.3 clean: the CLI VERIFIES and DRIVES the census. It holds NO authority:
|
|
15
|
+
* it cannot mint grants, accept rules on behalf of a child, publish the trust
|
|
16
|
+
* list, or carry billing. The census is the sole safety authority.
|
|
17
|
+
*/
|
|
18
|
+
import { Command } from "commander";
|
|
19
|
+
import { loadConfig } from "./config.js";
|
|
20
|
+
import { runInit } from "./commands/init.js";
|
|
21
|
+
import { runDoctor } from "./commands/doctor.js";
|
|
22
|
+
import { runCaps } from "./commands/caps.js";
|
|
23
|
+
import { runLinkWrite } from "./commands/link-write.js";
|
|
24
|
+
import { runGkCheck } from "./commands/gk-check.js";
|
|
25
|
+
import { runRegister } from "./commands/register.js";
|
|
26
|
+
const program = new Command("phosra")
|
|
27
|
+
.description("Phosra CLI — OCSS partner setup verification and sandbox round-trips")
|
|
28
|
+
.version("0.1.0");
|
|
29
|
+
// ── phosra init ─────────────────────────────────────────────────────────────
|
|
30
|
+
program
|
|
31
|
+
.command("init")
|
|
32
|
+
.description("Scaffold a .phosra.env wired to the staging shared sandbox — zero provisioning")
|
|
33
|
+
.option("-r, --role <role>", 'Integration role: "provider" or "platform"', "provider")
|
|
34
|
+
.option("-f, --force", "Overwrite existing .phosra.env", false)
|
|
35
|
+
.option("--json", "Machine-readable JSON output", false)
|
|
36
|
+
.action(async (opts) => {
|
|
37
|
+
const role = opts.role;
|
|
38
|
+
if (role !== "provider" && role !== "platform") {
|
|
39
|
+
console.error(`error: --role must be "provider" or "platform", got "${role}"`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
await runInit({ role, force: opts.force, json: opts.json });
|
|
43
|
+
});
|
|
44
|
+
// ── phosra register ──────────────────────────────────────────────────────────
|
|
45
|
+
//
|
|
46
|
+
// Phase 2a: self-serve cold onboarding. Generates a fresh Ed25519 keypair,
|
|
47
|
+
// registers the DID on the sandbox census as a provisional trust-list entry,
|
|
48
|
+
// and proves a verifiable rule-write round-trip — no email, no pre-seed.
|
|
49
|
+
//
|
|
50
|
+
// SANDBOX-ONLY: the census rejects this on production (SANDBOX_MODE guard).
|
|
51
|
+
program
|
|
52
|
+
.command("register")
|
|
53
|
+
.description("Cold-party onboarding: generate a fresh DID, self-register on the sandbox " +
|
|
54
|
+
"census as a provisional entry, and prove a green verifiable round-trip.\n" +
|
|
55
|
+
"SANDBOX ONLY — the census rejects self-registration in production.")
|
|
56
|
+
.option("--api-url <url>", "Census base URL (default: staging sandbox)")
|
|
57
|
+
.option("--trust-root-x <x>", "Trust-list root public key X (base64url-raw)")
|
|
58
|
+
.option("--slug <slug>", "Party slug for the DID (default: random p<hex>)")
|
|
59
|
+
.option("--out <path>", "Path for the .phosra.env file (default: .phosra.env in cwd)")
|
|
60
|
+
.option("--roles <roles>", "Comma-separated roles (default: editor)")
|
|
61
|
+
.option("--json", "Machine-readable JSON output", false)
|
|
62
|
+
.action(async (opts) => {
|
|
63
|
+
try {
|
|
64
|
+
const roles = opts.roles ? opts.roles.split(",").map((r) => r.trim()) : ["editor"];
|
|
65
|
+
const result = await runRegister({
|
|
66
|
+
apiUrl: opts.apiUrl,
|
|
67
|
+
trustRootX: opts.trustRootX,
|
|
68
|
+
slug: opts.slug,
|
|
69
|
+
out: opts.out,
|
|
70
|
+
roles,
|
|
71
|
+
});
|
|
72
|
+
if (opts.json) {
|
|
73
|
+
console.log(JSON.stringify(result, null, 2));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(`\nPASS — registered DID: ${result.PHOSRA_DID}`);
|
|
77
|
+
console.log(` trust tier: provisional`);
|
|
78
|
+
console.log(` census: ${result.PHOSRA_CENSUS_URL}`);
|
|
79
|
+
console.log(` env file: ${result.envFile}`);
|
|
80
|
+
console.log(`\nGREEN — your own DID completed a verifiable round-trip\n`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (opts.json) {
|
|
85
|
+
console.log(JSON.stringify({ error: String(err) }));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.error(`register failed: ${String(err)}`);
|
|
89
|
+
}
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
// ── phosra doctor ────────────────────────────────────────────────────────────
|
|
94
|
+
program
|
|
95
|
+
.command("doctor")
|
|
96
|
+
.description("Verify the whole OCSS setup end-to-end: census reachable, trust list verified, " +
|
|
97
|
+
"capabilities fetched, spec version negotiated, signed round-trip passes")
|
|
98
|
+
.option("--json", "Machine-readable JSON output (for CI/agents)", false)
|
|
99
|
+
.action(async (opts) => {
|
|
100
|
+
const cfg = loadConfig();
|
|
101
|
+
const results = await runDoctor(cfg, opts.json);
|
|
102
|
+
// runDoctor prints its own output; we set the exit code here.
|
|
103
|
+
const failed = results.filter((r) => r.status === "fail");
|
|
104
|
+
if (failed.length > 0)
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
107
|
+
// ── phosra caps ──────────────────────────────────────────────────────────────
|
|
108
|
+
program
|
|
109
|
+
.command("caps")
|
|
110
|
+
.description("Fetch, verify-to-root, and pretty-print the /.well-known/ocss/capabilities document")
|
|
111
|
+
.option("--json", "Machine-readable JSON output", false)
|
|
112
|
+
.action(async (opts) => {
|
|
113
|
+
const cfg = loadConfig();
|
|
114
|
+
await runCaps(cfg, opts.json);
|
|
115
|
+
// runCaps calls process.exit(1) on error; reaching here = success.
|
|
116
|
+
});
|
|
117
|
+
// ── phosra link ──────────────────────────────────────────────────────────────
|
|
118
|
+
const linkCmd = program
|
|
119
|
+
.command("link")
|
|
120
|
+
.description("Provider (parental-controls vendor) commands — drives @phosra/link SDK.\n" +
|
|
121
|
+
"Requires @phosra/link peer dep and PHOSRA_DATABASE_URL.");
|
|
122
|
+
linkCmd
|
|
123
|
+
.command("write <category>")
|
|
124
|
+
.description("Write a signed rule via the @phosra/link directive() — the metered binding leg.")
|
|
125
|
+
.requiredOption("--grant-id <id>", "Active grant ID from the connect ceremony")
|
|
126
|
+
.requiredOption("--child-ref <ref>", "Target child ref, e.g. child:<uuid>")
|
|
127
|
+
.option("--decision <d>", "block | warn | allow", "block")
|
|
128
|
+
.option("--json", "Machine-readable JSON output", false)
|
|
129
|
+
.action(async (category, opts) => {
|
|
130
|
+
const cfg = loadConfig();
|
|
131
|
+
const decision = (["block", "warn", "allow"].includes(opts.decision)
|
|
132
|
+
? opts.decision
|
|
133
|
+
: "block");
|
|
134
|
+
await runLinkWrite(cfg, { category, decision, grantId: opts.grantId, childRef: opts.childRef, json: opts.json });
|
|
135
|
+
});
|
|
136
|
+
// ── phosra gatekeeper ────────────────────────────────────────────────────────
|
|
137
|
+
const gkCmd = program
|
|
138
|
+
.command("gatekeeper")
|
|
139
|
+
.description("Platform commands — drives @phosra/gatekeeper SDK.\n" +
|
|
140
|
+
"Requires @phosra/gatekeeper peer dep and PHOSRA_ENDPOINT_ID.");
|
|
141
|
+
gkCmd
|
|
142
|
+
.command("check <category>")
|
|
143
|
+
.description("Refresh the enforcement profile and call isAllowed() for a rule category.")
|
|
144
|
+
.option("--endpoint-id <id>", "Override PHOSRA_ENDPOINT_ID")
|
|
145
|
+
.option("--confirm <state>", "Emit a §8.3.8 enforcement-confirmation: applied | degraded | refused")
|
|
146
|
+
.option("--json", "Machine-readable JSON output", false)
|
|
147
|
+
.action(async (category, opts) => {
|
|
148
|
+
const cfg = loadConfig();
|
|
149
|
+
const confirm = (["applied", "degraded", "refused"].includes(opts.confirm ?? "")
|
|
150
|
+
? opts.confirm
|
|
151
|
+
: undefined);
|
|
152
|
+
await runGkCheck(cfg, { category, endpointId: opts.endpointId, confirm, json: opts.json });
|
|
153
|
+
});
|
|
154
|
+
// ── entrypoint ───────────────────────────────────────────────────────────────
|
|
155
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
156
|
+
console.error("fatal:", err);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
|
159
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* phosra caps — fetch + root-verify + pretty-print the capabilities document.
|
|
3
|
+
*
|
|
4
|
+
* Reads /.well-known/ocss/capabilities from the census, verifies the Ed25519
|
|
5
|
+
* root signature (same path as phosra doctor check 3, but standalone + verbose),
|
|
6
|
+
* then renders the supported lanes, rule categories, and version range.
|
|
7
|
+
*
|
|
8
|
+
* §12.3: verification only — the CLI never publishes or rotates the caps doc.
|
|
9
|
+
* The census is the sole publisher; `ops caps publish` (future Go binary) is
|
|
10
|
+
* the operator path.
|
|
11
|
+
*/
|
|
12
|
+
import type { PhosraConfig } from "../config.js";
|
|
13
|
+
type FetchImpl = typeof fetch;
|
|
14
|
+
export declare function runCaps(cfg: PhosraConfig, json: boolean, fetchImpl?: FetchImpl): Promise<void>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=caps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caps.d.ts","sourceRoot":"","sources":["../../src/commands/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,KAAK,SAAS,GAAG,OAAO,KAAK,CAAC;AAU9B,wBAAsB,OAAO,CAC3B,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,SAAiB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAgHf"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* phosra caps — fetch + root-verify + pretty-print the capabilities document.
|
|
3
|
+
*
|
|
4
|
+
* Reads /.well-known/ocss/capabilities from the census, verifies the Ed25519
|
|
5
|
+
* root signature (same path as phosra doctor check 3, but standalone + verbose),
|
|
6
|
+
* then renders the supported lanes, rule categories, and version range.
|
|
7
|
+
*
|
|
8
|
+
* §12.3: verification only — the CLI never publishes or rotates the caps doc.
|
|
9
|
+
* The census is the sole publisher; `ops caps publish` (future Go binary) is
|
|
10
|
+
* the operator path.
|
|
11
|
+
*/
|
|
12
|
+
import { verifyCapabilitiesDocument, } from "@openchildsafety/ocss";
|
|
13
|
+
import { printJson, heading, note } from "../out.js";
|
|
14
|
+
const C = {
|
|
15
|
+
bold: (s) => process.stdout.isTTY ? `\x1b[1m${s}\x1b[0m` : s,
|
|
16
|
+
green: (s) => process.stdout.isTTY ? `\x1b[32m${s}\x1b[0m` : s,
|
|
17
|
+
dim: (s) => process.stdout.isTTY ? `\x1b[2m${s}\x1b[0m` : s,
|
|
18
|
+
cyan: (s) => process.stdout.isTTY ? `\x1b[36m${s}\x1b[0m` : s,
|
|
19
|
+
yellow: (s) => process.stdout.isTTY ? `\x1b[33m${s}\x1b[0m` : s,
|
|
20
|
+
};
|
|
21
|
+
export async function runCaps(cfg, json, fetchImpl = fetch) {
|
|
22
|
+
heading("Phosra caps", json);
|
|
23
|
+
const url = `${cfg.censusUrl}/.well-known/ocss/capabilities`;
|
|
24
|
+
let signed;
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetchImpl(url, { method: "GET" });
|
|
27
|
+
if (res.status === 404) {
|
|
28
|
+
if (json) {
|
|
29
|
+
printJson({ ok: false, error: "not_found", url });
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log(` ${C.yellow("⚠")} Capabilities doc not published at this census (P1 feature)\n` +
|
|
33
|
+
C.dim(` URL: ${url}`));
|
|
34
|
+
}
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
if (json) {
|
|
39
|
+
printJson({ ok: false, error: `http_${res.status}`, url });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.error(` ✘ HTTP ${res.status} from ${url}`);
|
|
43
|
+
}
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
signed = (await res.json());
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (json) {
|
|
50
|
+
printJson({ ok: false, error: "network_error", message: err.message });
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.error(` ✘ Network error: ${err.message}`);
|
|
54
|
+
}
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
let doc;
|
|
58
|
+
try {
|
|
59
|
+
doc = verifyCapabilitiesDocument(signed, cfg.trustRootX);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (json) {
|
|
63
|
+
printJson({
|
|
64
|
+
ok: false,
|
|
65
|
+
error: "verification_failed",
|
|
66
|
+
message: err.message,
|
|
67
|
+
trust_root_x: cfg.trustRootX,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.error(` ✘ Verification failed: ${err.message}`);
|
|
72
|
+
console.error(C.dim(` Check PHOSRA_TRUST_ROOT_X: ${cfg.trustRootX}`));
|
|
73
|
+
}
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
if (json) {
|
|
77
|
+
printJson({
|
|
78
|
+
ok: true,
|
|
79
|
+
url,
|
|
80
|
+
ocss_version: doc.ocss_version,
|
|
81
|
+
serial: doc.serial,
|
|
82
|
+
not_after: doc.not_after,
|
|
83
|
+
version_range: doc.version_range,
|
|
84
|
+
rule_categories: doc.rule_categories,
|
|
85
|
+
decision_verbs: doc.decision_verbs,
|
|
86
|
+
param_families: doc.param_families,
|
|
87
|
+
rating_crosswalk_ordinals: doc.rating_crosswalk_ordinals,
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// ── human render ──────────────────────────────────────────────────────────
|
|
92
|
+
console.log(` ${C.green("✔")} Verified to root ` +
|
|
93
|
+
C.dim(`(${cfg.trustRootX.slice(0, 12)}…)`) +
|
|
94
|
+
"\n");
|
|
95
|
+
console.log(` ${C.bold("OCSS version:")} ${doc.ocss_version}`);
|
|
96
|
+
console.log(` ${C.bold("Serial:")} ${doc.serial}`);
|
|
97
|
+
console.log(` ${C.bold("Not after:")} ${doc.not_after}`);
|
|
98
|
+
const supported = doc.version_range?.supported ?? [];
|
|
99
|
+
console.log(` ${C.bold("Version range:")} ${supported.join(", ") || "(none)"}`);
|
|
100
|
+
const rules = doc.rule_categories ?? [];
|
|
101
|
+
if (rules.length > 0) {
|
|
102
|
+
console.log(`\n ${C.bold(`Rule categories (${rules.length}):`)}`);
|
|
103
|
+
// Group by tier for compact display
|
|
104
|
+
const byTier = {};
|
|
105
|
+
for (const r of rules) {
|
|
106
|
+
(byTier[r.tier] ??= []).push(r);
|
|
107
|
+
}
|
|
108
|
+
for (const [tier, cats] of Object.entries(byTier)) {
|
|
109
|
+
console.log(`\n ${C.cyan(tier.toUpperCase())}`);
|
|
110
|
+
for (const c of cats) {
|
|
111
|
+
const floor = c.floor ? C.dim(` [floor: ${c.floor}]`) : "";
|
|
112
|
+
console.log(` ${C.dim("·")} ${c.slug}${floor}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const verbs = doc.decision_verbs ?? [];
|
|
117
|
+
if (verbs.length > 0) {
|
|
118
|
+
console.log(`\n ${C.bold(`Decision verbs (${verbs.length}):`)}`);
|
|
119
|
+
for (const v of verbs) {
|
|
120
|
+
console.log(` ${C.dim("·")} ${v.verb} ${C.dim(`fallback=${v.fallback} class=${v.safety_class}`)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
note(`Source: ${url}`, json);
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=caps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caps.js","sourceRoot":"","sources":["../../src/commands/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,0BAA0B,GAG3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIrD,MAAM,CAAC,GAAG;IACR,IAAI,EAAG,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAE,CAAC,CAAC,CAAC;IACtE,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACtE,GAAG,EAAI,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAE,CAAC,CAAC,CAAC;IACtE,IAAI,EAAG,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,EAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;CACvE,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAiB,EACjB,IAAa,EACb,YAAuB,KAAK;IAE5B,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAE7B,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,SAAS,gCAAgC,CAAC;IAC7D,IAAI,MAAsB,CAAC;IAE3B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACpD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,IAAI,IAAI,EAAE,CAAC;gBACT,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,gEAAgE;oBAClF,CAAC,CAAC,GAAG,CAAC,aAAa,GAAG,EAAE,CAAC,CAC1B,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,IAAI,EAAE,CAAC;gBACT,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC;YACvD,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmB,CAAC;IAChD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,IAAI,EAAE,CAAC;YACT,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACpF,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,uBAAwB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,GAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,GAAG,GAAG,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,IAAI,EAAE,CAAC;YACT,SAAS,CAAC;gBACR,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,qBAAqB;gBAC5B,OAAO,EAAG,GAAa,CAAC,OAAO;gBAC/B,YAAY,EAAE,GAAG,CAAC,UAAU;aAC7B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,6BAA8B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,mCAAmC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,IAAI,EAAE,CAAC;QACT,SAAS,CAAC;YACR,EAAE,EAAE,IAAI;YACR,GAAG;YACH,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,eAAe,EAAE,GAAG,CAAC,eAAe;YACpC,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,yBAAyB,EAAE,GAAG,CAAC,yBAAyB;SACzD,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB;QACvC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;QAC1C,IAAI,CACL,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;IAE/D,MAAM,SAAS,GAAG,GAAG,CAAC,aAAa,EAAE,SAAS,IAAI,EAAE,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;IAElF,MAAM,KAAK,GAAG,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,oBAAoB,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC;QACnE,oCAAoC;QACpC,MAAM,MAAM,GAAiC,EAAE,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3D,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;IACvC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC;QAClE,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CACT,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,QAAQ,WAAW,CAAC,CAAC,YAAY,EAAE,CAAC,EAAE,CAC3F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,CAAC,WAAW,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* phosra doctor — end-to-end setup verification.
|
|
3
|
+
*
|
|
4
|
+
* Runs 5 checks in order, reporting PASS / FAIL / WARN for each.
|
|
5
|
+
* Exits 0 if all checks pass (warns are non-fatal). Exits 1 on any FAIL.
|
|
6
|
+
*
|
|
7
|
+
* Checks:
|
|
8
|
+
* 1. census_reachable GET /health → 200
|
|
9
|
+
* 2. trust_list_verified GET /.well-known/ocss/trust-list + Ed25519 root-sig verify
|
|
10
|
+
* 3. caps_verified GET /.well-known/ocss/capabilities + root-sig verify (WARN if 404)
|
|
11
|
+
* 4. version_negotiates negotiate(SUPPORTED_VERSIONS, caps.version_range.supported)
|
|
12
|
+
* 5. sandbox_round_trip Full §8.3.2 + §8.3.1 write cycle via runProviderRoundTrip:
|
|
13
|
+
* trust-list fetch → router JWK extract →
|
|
14
|
+
* consent_attestation ingest (201) → rule write (201)
|
|
15
|
+
*
|
|
16
|
+
* Check 5 uses the zero-provisioning sandbox: household-acme against the STAGING
|
|
17
|
+
* shared sandbox trust-list + Mia child/policy — no DB, no per-org provisioning,
|
|
18
|
+
* no extra backend.
|
|
19
|
+
*
|
|
20
|
+
* §12.3: census is the safety authority. The CLI verifies; it never decides.
|
|
21
|
+
* Fail-closed: any FAIL exits non-zero, never a false green.
|
|
22
|
+
*/
|
|
23
|
+
import type { PhosraConfig } from "../config.js";
|
|
24
|
+
import { type CheckResult } from "../out.js";
|
|
25
|
+
type FetchImpl = typeof fetch;
|
|
26
|
+
/**
|
|
27
|
+
* Run all doctor checks.
|
|
28
|
+
* Returns the array of CheckResults; the caller (bin.ts) sets the exit code.
|
|
29
|
+
*
|
|
30
|
+
* fetchImpl is injectable for unit tests — real commands pass global fetch.
|
|
31
|
+
*/
|
|
32
|
+
export declare function runDoctor(cfg: PhosraConfig, json: boolean, fetchImpl?: FetchImpl): Promise<CheckResult[]>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAYH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,OAAO,EACL,KAAK,WAAW,EAKjB,MAAM,WAAW,CAAC;AAEnB,KAAK,SAAS,GAAG,OAAO,KAAK,CAAC;AAE9B;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,OAAO,EACb,SAAS,GAAE,SAAiB,GAC3B,OAAO,CAAC,WAAW,EAAE,CAAC,CA0DxB"}
|