@axtary/actionpass 0.1.0 → 0.3.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.
@@ -0,0 +1,104 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // Dev keypair helper (PRD §8.2 developer experience; mega-plan M8.2)
3
+ //
4
+ // The SDK facade signs ActionPasses with an issuer key. In production a
5
+ // developer supplies their own key (or a hosted issuer); for local development
6
+ // we want zero manual JWK plumbing while still producing passes that verify
7
+ // across process restarts (an ephemeral per-process key cannot).
8
+ //
9
+ // `devKeypair()` resolves a stable ES256 keypair with no key code:
10
+ // 1. caller-supplied env — optional AXTARY_DEV_SIGNING_KEY for CI/containers
11
+ // 2. a local keyring file — default .axtary/sdk-dev-keyring.json (0600, gitignored)
12
+ // Both survive restarts. Spread the result directly into createAxtary():
13
+ // const sdk = createAxtary(await devKeypair());
14
+ //
15
+ // This adds no new authorization or token/ledger/policy shape; it only produces
16
+ // the same { signingKey, verificationKey } the facade already accepts, reusing
17
+ // the existing persistent issuer-keyring primitive (status-list.ts).
18
+ // ─────────────────────────────────────────────────────────────────────────────
19
+ import { createPrivateKey, createPublicKey } from "node:crypto";
20
+ import { join } from "node:path";
21
+ import { exportJWK } from "jose";
22
+ import { issuerSigningKey, loadOrCreateIssuerKeyring } from "./status-list.js";
23
+ /** Env var holding an ES256 private key (PEM, or base64-encoded PEM). */
24
+ export const AXTARY_DEV_SIGNING_KEY_ENV = "AXTARY_DEV_SIGNING_KEY";
25
+ /** Optional env var overriding the dev key id (`kid`). */
26
+ export const AXTARY_DEV_KEY_ID_ENV = "AXTARY_DEV_KEY_ID";
27
+ /** Env var pointing the local keyring at a directory other than ./.axtary. */
28
+ export const AXTARY_HOME_ENV = "AXTARY_HOME";
29
+ /** Filename of the file-backed dev keyring inside the resolved home dir. */
30
+ export const AXTARY_DEV_KEYRING_FILENAME = "sdk-dev-keyring.json";
31
+ /** Default `kid` for an env-backed dev key when none is supplied. */
32
+ export const AXTARY_DEFAULT_DEV_KEY_ID = "axtary-dev";
33
+ /**
34
+ * Resolve the file-backed dev keyring path: an explicit override, else
35
+ * `$AXTARY_HOME/sdk-dev-keyring.json`, else project-local
36
+ * `.axtary/sdk-dev-keyring.json`.
37
+ */
38
+ export function resolveDevKeyringPath(options = {}) {
39
+ if (options.path) {
40
+ return options.path;
41
+ }
42
+ const env = options.env ?? {};
43
+ const home = env[AXTARY_HOME_ENV];
44
+ if (home && home.trim().length > 0) {
45
+ return join(home, AXTARY_DEV_KEYRING_FILENAME);
46
+ }
47
+ return join(".axtary", AXTARY_DEV_KEYRING_FILENAME);
48
+ }
49
+ function pemFromEnvValue(raw) {
50
+ const trimmed = raw.trim();
51
+ if (trimmed.includes("-----BEGIN")) {
52
+ return trimmed;
53
+ }
54
+ // Single-line base64 / base64url-encoded PEM (env-var friendly).
55
+ return Buffer.from(trimmed, "base64").toString("utf8");
56
+ }
57
+ async function envBackedKey(env) {
58
+ const raw = env[AXTARY_DEV_SIGNING_KEY_ENV];
59
+ if (!raw || raw.trim().length === 0) {
60
+ return null;
61
+ }
62
+ const signingKey = createPrivateKey(pemFromEnvValue(raw));
63
+ const verificationKey = await exportJWK(createPublicKey(signingKey));
64
+ verificationKey.alg = "ES256";
65
+ const keyId = env[AXTARY_DEV_KEY_ID_ENV];
66
+ return {
67
+ signingKey,
68
+ verificationKey,
69
+ signingKeyId: keyId && keyId.trim().length > 0 ? keyId : AXTARY_DEFAULT_DEV_KEY_ID,
70
+ algorithm: "ES256",
71
+ source: "env",
72
+ };
73
+ }
74
+ /**
75
+ * Resolve a stable, persistent ES256 dev keypair with zero manual JWK code.
76
+ * Resolution order: caller-supplied AXTARY_DEV_SIGNING_KEY (env-backed, shared
77
+ * across processes) → a local keyring file (default
78
+ * `.axtary/sdk-dev-keyring.json`, `0600`, gitignored). Both verify across
79
+ * process restarts. Pass the result straight to the SDK:
80
+ * `createAxtary(await devKeypair())`.
81
+ *
82
+ * This is a development convenience. For production use a real issuer key or a
83
+ * hosted issuer; the file-backed key never leaves the machine and the env-backed
84
+ * key is whatever the operator provisions.
85
+ */
86
+ export async function devKeypair(options = {}) {
87
+ const env = options.env ?? {};
88
+ const fromEnv = await envBackedKey(env);
89
+ if (fromEnv) {
90
+ return fromEnv;
91
+ }
92
+ const path = resolveDevKeyringPath(options);
93
+ const keyring = await loadOrCreateIssuerKeyring(path);
94
+ const signer = issuerSigningKey(keyring);
95
+ return {
96
+ signingKey: signer.privateKey,
97
+ verificationKey: { ...signer.publicJwk, alg: "ES256" },
98
+ signingKeyId: signer.kid,
99
+ algorithm: "ES256",
100
+ source: "file",
101
+ path,
102
+ };
103
+ }
104
+ //# sourceMappingURL=dev-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-key.js","sourceRoot":"","sources":["../src/dev-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { PolicyDecision } from "./index.js";
2
+ export type PolicyDecisionExplanation = {
3
+ label: string;
4
+ summary: string;
5
+ reviewerAction: "none" | "block" | "approval_required";
6
+ reasonDetails: Array<{
7
+ reason: string;
8
+ detail: string;
9
+ }>;
10
+ };
11
+ export declare function explainDecision(decisionInput: PolicyDecision): PolicyDecisionExplanation;
12
+ //# sourceMappingURL=explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,OAAO,GAAG,mBAAmB,CAAC;IACvD,aAAa,EAAE,KAAK,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ,CAAC;AAEF,wBAAgB,eAAe,CAC7B,aAAa,EAAE,cAAc,GAC5B,yBAAyB,CAqB3B"}
@@ -0,0 +1,156 @@
1
+ // Deterministic, human-readable explanation of a policy decision.
2
+ //
3
+ // This is the canonical reason→prose map for Axtary. It lives in the base
4
+ // `@axtary/actionpass` package so both the SDK facade (`axtary.explain`) and the
5
+ // policy/CLI surfaces share one source of truth instead of duplicating prose.
6
+ // `@axtary/policy` re-exports `explainPolicyDecision` from here for backward
7
+ // compatibility. It is intentionally deterministic — no model call — so the same
8
+ // decision always produces the same explanation.
9
+ export function explainDecision(decisionInput) {
10
+ const reviewerAction = decisionInput.decision === "allow"
11
+ ? "none"
12
+ : decisionInput.decision === "step_up"
13
+ ? "approval_required"
14
+ : "block";
15
+ const label = decisionInput.decision === "allow"
16
+ ? "Allowed"
17
+ : decisionInput.decision === "step_up"
18
+ ? "Step-up required"
19
+ : "Denied";
20
+ return {
21
+ label,
22
+ reviewerAction,
23
+ summary: decisionSummary(decisionInput),
24
+ reasonDetails: decisionInput.reasons.map((reason) => ({
25
+ reason,
26
+ detail: reasonDetail(reason),
27
+ })),
28
+ };
29
+ }
30
+ function decisionSummary(decisionInput) {
31
+ if (decisionInput.decision === "allow") {
32
+ return "The normalized action is inside the active policy and can proceed through ActionPass issuance.";
33
+ }
34
+ if (decisionInput.decision === "step_up") {
35
+ return "The normalized action is in scope only after exact payload-bound reviewer approval.";
36
+ }
37
+ return "The normalized action is outside the active policy and must not execute.";
38
+ }
39
+ function reasonDetail(reason) {
40
+ if (reason === "github_pr_inside_policy") {
41
+ return "Base branch, changed paths, file count, and test evidence satisfy the GitHub PR rule.";
42
+ }
43
+ if (reason === "github_content_write_inside_policy") {
44
+ return "The write path and branch are inside the configured repository guardrails.";
45
+ }
46
+ if (reason === "github_review_protected_path_step_up") {
47
+ return "The inline review targets a protected path and requires exact payload-bound approval.";
48
+ }
49
+ if (reason === "github_review_comment_inside_policy") {
50
+ return "The inline review target and exact comment body satisfy the repository guardrails.";
51
+ }
52
+ if (reason === "github_check_run_inside_policy") {
53
+ return "The check name, commit SHA, state, conclusion, and output are structurally valid and payload-bound.";
54
+ }
55
+ if (reason === "github_issue_comment_inside_policy") {
56
+ return "The issue number and exact outbound comment body are structurally valid and payload-bound.";
57
+ }
58
+ if (reason === "postgres_select_inside_policy") {
59
+ return "The parameterized SELECT, database, tables, functions, predicate, and row cap are inside the configured read scope.";
60
+ }
61
+ if (reason === "postgres_unpredicated_scan_step_up") {
62
+ return "The SELECT has no row predicate and requires exact payload-bound approval before the adapter can connect.";
63
+ }
64
+ if (reason === "postgres_select_only") {
65
+ return "Only one parsed SELECT statement is executable through the Postgres connector.";
66
+ }
67
+ if (reason === "postgres_table_not_allowed") {
68
+ return "At least one referenced table is outside the configured Postgres allowlist.";
69
+ }
70
+ if (reason === "github_branch_inside_policy") {
71
+ return "The branch creation request is tied to the configured base branch.";
72
+ }
73
+ if (reason === "content_read_denied_path") {
74
+ return "The requested file path matches a protected content-read prefix.";
75
+ }
76
+ if (reason === "payload_touches_denied_path") {
77
+ return "The payload touches a path prefix that policy blocks outright.";
78
+ }
79
+ if (reason === "payload_touches_step_up_path") {
80
+ return "The payload touches a protected path prefix that requires exact review.";
81
+ }
82
+ if (reason === "payload_touches_protected_path") {
83
+ return "The payload touches a protected path prefix and requires exact review.";
84
+ }
85
+ if (reason === "file_count_exceeds_policy_limit") {
86
+ return "The PR changes more files than the active policy allows without review.";
87
+ }
88
+ if (reason === "tests_required_before_pr") {
89
+ return "The PR payload does not include passing test evidence required by policy.";
90
+ }
91
+ if (reason === "payload_declares_production_impact") {
92
+ return "The action declares production impact, so reviewer approval is required.";
93
+ }
94
+ if (reason === "slack_channel_not_allowed") {
95
+ return "The Slack channel is not in the configured allowlist.";
96
+ }
97
+ if (reason === "slack_external_recipient_step_up") {
98
+ return "The message reaches external recipients and must be reviewed exactly.";
99
+ }
100
+ if (reason === "provenance_unknown_egress") {
101
+ return "A covered outbound field has no authority-stamped source lineage, so policy fails closed.";
102
+ }
103
+ if (reason === "provenance_untrusted_egress") {
104
+ return "A covered outbound field derives from untrusted document or tool output and requires exact review.";
105
+ }
106
+ if (reason === "linear_status_requires_step_up") {
107
+ return "The Linear status transition targets a configured protected status.";
108
+ }
109
+ if (reason === "jira_status_requires_step_up") {
110
+ return "The Jira status transition targets a configured protected status.";
111
+ }
112
+ if (reason.endsWith("_project_not_allowed")) {
113
+ return "The issue project key is outside the configured tracker allowlist.";
114
+ }
115
+ if (reason === "docs_search_inside_policy") {
116
+ return "The document search request stays inside the configured workspace and result limit.";
117
+ }
118
+ if (reason === "docs_read_inside_policy") {
119
+ return "The document path and requested byte limit are inside the configured documentation scope.";
120
+ }
121
+ if (reason === "docs_workspace_not_allowed") {
122
+ return "The document workspace is outside the configured allowlist.";
123
+ }
124
+ if (reason === "docs_path_denied") {
125
+ return "The requested document path matches a protected documentation prefix.";
126
+ }
127
+ if (reason === "docs_path_not_allowed") {
128
+ return "The requested document path is outside the configured documentation prefixes.";
129
+ }
130
+ if (reason === "docs_result_limit_exceeds_policy") {
131
+ return "The search request asks for more document results than policy allows.";
132
+ }
133
+ if (reason === "docs_read_bytes_exceeds_policy") {
134
+ return "The read request asks for more document bytes than policy allows.";
135
+ }
136
+ if (reason === "payload_is_inside_current_actionpass_constraints") {
137
+ return "The payload is inside the constraints carried by the current ActionPass.";
138
+ }
139
+ if (reason.startsWith("unsupported_tool:")) {
140
+ return "The tool is not supported by the native policy evaluator and fails closed.";
141
+ }
142
+ if (reason.startsWith("base_branch_mismatch:")) {
143
+ return "The requested base branch differs from the configured branch and needs review.";
144
+ }
145
+ if (reason === "approval_payload_hash_mismatch") {
146
+ return "The payload differs from the exact payload the human approval was granted on, so execution is denied.";
147
+ }
148
+ if (reason === "approval_action_hash_mismatch") {
149
+ return "The action differs from the exact action the human approval was granted on, so execution is denied.";
150
+ }
151
+ if (reason.startsWith("approved_payload_hash:")) {
152
+ return "The payload hash the human approval was actually bound to, kept as evidence beside the mismatch.";
153
+ }
154
+ return "The active native policy emitted this reason for the normalized action.";
155
+ }
156
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"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"}