@groundnuty/macf 0.2.0-rc.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.
Files changed (124) hide show
  1. package/dist/.build-info.json +4 -0
  2. package/dist/cli/build-info.d.ts +38 -0
  3. package/dist/cli/build-info.d.ts.map +1 -0
  4. package/dist/cli/build-info.js +119 -0
  5. package/dist/cli/build-info.js.map +1 -0
  6. package/dist/cli/claude-sh.d.ts +42 -0
  7. package/dist/cli/claude-sh.d.ts.map +1 -0
  8. package/dist/cli/claude-sh.js +247 -0
  9. package/dist/cli/claude-sh.js.map +1 -0
  10. package/dist/cli/commands/cd.d.ts +6 -0
  11. package/dist/cli/commands/cd.d.ts.map +1 -0
  12. package/dist/cli/commands/cd.js +17 -0
  13. package/dist/cli/commands/cd.js.map +1 -0
  14. package/dist/cli/commands/certs.d.ts +33 -0
  15. package/dist/cli/commands/certs.d.ts.map +1 -0
  16. package/dist/cli/commands/certs.js +233 -0
  17. package/dist/cli/commands/certs.js.map +1 -0
  18. package/dist/cli/commands/doctor.d.ts +91 -0
  19. package/dist/cli/commands/doctor.d.ts.map +1 -0
  20. package/dist/cli/commands/doctor.js +235 -0
  21. package/dist/cli/commands/doctor.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +37 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +279 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/commands/list.d.ts +5 -0
  27. package/dist/cli/commands/list.d.ts.map +1 -0
  28. package/dist/cli/commands/list.js +21 -0
  29. package/dist/cli/commands/list.js.map +1 -0
  30. package/dist/cli/commands/migrate-ca-key.d.ts +36 -0
  31. package/dist/cli/commands/migrate-ca-key.d.ts.map +1 -0
  32. package/dist/cli/commands/migrate-ca-key.js +92 -0
  33. package/dist/cli/commands/migrate-ca-key.js.map +1 -0
  34. package/dist/cli/commands/peers.d.ts +8 -0
  35. package/dist/cli/commands/peers.d.ts.map +1 -0
  36. package/dist/cli/commands/peers.js +45 -0
  37. package/dist/cli/commands/peers.js.map +1 -0
  38. package/dist/cli/commands/repo-init.d.ts +43 -0
  39. package/dist/cli/commands/repo-init.d.ts.map +1 -0
  40. package/dist/cli/commands/repo-init.js +304 -0
  41. package/dist/cli/commands/repo-init.js.map +1 -0
  42. package/dist/cli/commands/rules-refresh.d.ts +14 -0
  43. package/dist/cli/commands/rules-refresh.d.ts.map +1 -0
  44. package/dist/cli/commands/rules-refresh.js +67 -0
  45. package/dist/cli/commands/rules-refresh.js.map +1 -0
  46. package/dist/cli/commands/self-update.d.ts +14 -0
  47. package/dist/cli/commands/self-update.d.ts.map +1 -0
  48. package/dist/cli/commands/self-update.js +112 -0
  49. package/dist/cli/commands/self-update.js.map +1 -0
  50. package/dist/cli/commands/status.d.ts +9 -0
  51. package/dist/cli/commands/status.d.ts.map +1 -0
  52. package/dist/cli/commands/status.js +90 -0
  53. package/dist/cli/commands/status.js.map +1 -0
  54. package/dist/cli/commands/update.d.ts +25 -0
  55. package/dist/cli/commands/update.d.ts.map +1 -0
  56. package/dist/cli/commands/update.js +316 -0
  57. package/dist/cli/commands/update.js.map +1 -0
  58. package/dist/cli/config.d.ts +103 -0
  59. package/dist/cli/config.d.ts.map +1 -0
  60. package/dist/cli/config.js +224 -0
  61. package/dist/cli/config.js.map +1 -0
  62. package/dist/cli/index.d.ts +3 -0
  63. package/dist/cli/index.d.ts.map +1 -0
  64. package/dist/cli/index.js +245 -0
  65. package/dist/cli/index.js.map +1 -0
  66. package/dist/cli/plugin-fetcher.d.ts +20 -0
  67. package/dist/cli/plugin-fetcher.d.ts.map +1 -0
  68. package/dist/cli/plugin-fetcher.js +83 -0
  69. package/dist/cli/plugin-fetcher.js.map +1 -0
  70. package/dist/cli/prompt.d.ts +17 -0
  71. package/dist/cli/prompt.d.ts.map +1 -0
  72. package/dist/cli/prompt.js +109 -0
  73. package/dist/cli/prompt.js.map +1 -0
  74. package/dist/cli/registry-helper.d.ts +11 -0
  75. package/dist/cli/registry-helper.d.ts.map +1 -0
  76. package/dist/cli/registry-helper.js +18 -0
  77. package/dist/cli/registry-helper.js.map +1 -0
  78. package/dist/cli/rules.d.ts +39 -0
  79. package/dist/cli/rules.d.ts.map +1 -0
  80. package/dist/cli/rules.js +112 -0
  81. package/dist/cli/rules.js.map +1 -0
  82. package/dist/cli/settings-writer.d.ts +97 -0
  83. package/dist/cli/settings-writer.d.ts.map +1 -0
  84. package/dist/cli/settings-writer.js +270 -0
  85. package/dist/cli/settings-writer.js.map +1 -0
  86. package/dist/cli/version-resolver.d.ts +73 -0
  87. package/dist/cli/version-resolver.d.ts.map +1 -0
  88. package/dist/cli/version-resolver.js +238 -0
  89. package/dist/cli/version-resolver.js.map +1 -0
  90. package/dist/index.d.ts +19 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +22 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/plugin/bin/macf-plugin-cli.d.ts +13 -0
  95. package/dist/plugin/bin/macf-plugin-cli.d.ts.map +1 -0
  96. package/dist/plugin/bin/macf-plugin-cli.js +127 -0
  97. package/dist/plugin/bin/macf-plugin-cli.js.map +1 -0
  98. package/dist/plugin/lib/format.d.ts +40 -0
  99. package/dist/plugin/lib/format.d.ts.map +1 -0
  100. package/dist/plugin/lib/format.js +137 -0
  101. package/dist/plugin/lib/format.js.map +1 -0
  102. package/dist/plugin/lib/health.d.ts +2 -0
  103. package/dist/plugin/lib/health.d.ts.map +1 -0
  104. package/dist/plugin/lib/health.js +6 -0
  105. package/dist/plugin/lib/health.js.map +1 -0
  106. package/dist/plugin/lib/index.d.ts +7 -0
  107. package/dist/plugin/lib/index.d.ts.map +1 -0
  108. package/dist/plugin/lib/index.js +5 -0
  109. package/dist/plugin/lib/index.js.map +1 -0
  110. package/dist/plugin/lib/registry.d.ts +18 -0
  111. package/dist/plugin/lib/registry.d.ts.map +1 -0
  112. package/dist/plugin/lib/registry.js +17 -0
  113. package/dist/plugin/lib/registry.js.map +1 -0
  114. package/dist/plugin/lib/work.d.ts +13 -0
  115. package/dist/plugin/lib/work.d.ts.map +1 -0
  116. package/dist/plugin/lib/work.js +27 -0
  117. package/dist/plugin/lib/work.js.map +1 -0
  118. package/package.json +43 -0
  119. package/plugin/rules/coordination.md +224 -0
  120. package/scripts/check-gh-token.sh +102 -0
  121. package/scripts/macf-gh-token.sh +130 -0
  122. package/scripts/macf-whoami.sh +51 -0
  123. package/scripts/tmux-send-to-claude.sh +51 -0
  124. package/scripts/write-build-info.mjs +48 -0
@@ -0,0 +1,233 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readAgentConfig, agentCertPath, agentKeyPath, caCertPath as caCertPathFor, caKeyPath as caKeyPathFor, caDir, tokenSourceFromConfig, } from '../config.js';
4
+ import { createCA, backupCAKey, recoverCAKey, loadCA } from '@groundnuty/macf-core';
5
+ import { generateAgentCert, generateClientCert } from '@groundnuty/macf-core';
6
+ import { createClientFromConfig } from '../registry-helper.js';
7
+ import { createRegistryFromConfig } from '@groundnuty/macf-core';
8
+ import { generateToken } from '@groundnuty/macf-core';
9
+ import { promptPassword, PromptCancelled } from '../prompt.js';
10
+ import { toVariableSegment } from '@groundnuty/macf-core';
11
+ const ROUTING_CLIENT_CN = 'routing-action';
12
+ const DEFAULT_VALIDITY_DAYS = 365;
13
+ const VALIDITY_WARN_DAYS = 730;
14
+ async function promptPassphrase(message) {
15
+ try {
16
+ return await promptPassword({ message });
17
+ }
18
+ catch (err) {
19
+ if (err instanceof PromptCancelled) {
20
+ console.error('\nCancelled.');
21
+ process.exit(130); // 128 + SIGINT
22
+ }
23
+ throw err;
24
+ }
25
+ }
26
+ function getVariablesClient(config, token) {
27
+ if (!config)
28
+ throw new Error('No macf-agent.json found. Run `macf init` first.');
29
+ return createClientFromConfig(config.registry, token);
30
+ }
31
+ /**
32
+ * macf certs init: create CA, upload cert + encrypted key to registry
33
+ */
34
+ export async function certsInit(projectDir) {
35
+ const config = readAgentConfig(projectDir);
36
+ if (!config) {
37
+ console.error('No macf-agent.json found. Run `macf init` first.');
38
+ process.exitCode = 1;
39
+ return;
40
+ }
41
+ const token = await generateToken(tokenSourceFromConfig(projectDir, config));
42
+ const client = getVariablesClient(config, token);
43
+ // Per-project CA paths. mkdir with 0o700 — CA key is the most sensitive secret.
44
+ const projectCaDir = caDir(config.project);
45
+ mkdirSync(projectCaDir, { recursive: true, mode: 0o700 });
46
+ const caCertP = caCertPathFor(config.project);
47
+ const caKeyP = caKeyPathFor(config.project);
48
+ console.log(`Creating CA for project "${config.project}"...`);
49
+ const ca = await createCA({
50
+ project: config.project,
51
+ certPath: caCertP,
52
+ keyPath: caKeyP,
53
+ client,
54
+ });
55
+ console.log(` CA cert: ${caCertP}`);
56
+ console.log(` CA key: ${caKeyP}`);
57
+ console.log(` CA cert uploaded to registry as ${toVariableSegment(config.project)}_CA_CERT`);
58
+ // Encrypted backup
59
+ const passphrase = await promptPassphrase('Enter passphrase for CA key backup: ');
60
+ if (!passphrase) {
61
+ console.warn('No passphrase provided — skipping encrypted backup.');
62
+ return;
63
+ }
64
+ await backupCAKey({
65
+ project: config.project,
66
+ keyPem: ca.keyPem,
67
+ passphrase,
68
+ client,
69
+ });
70
+ console.log(` Encrypted CA key backed up to registry as ${toVariableSegment(config.project)}_CA_KEY_ENCRYPTED`);
71
+ console.log('\nCA initialization complete.');
72
+ }
73
+ /**
74
+ * macf certs recover: download and decrypt CA key from registry
75
+ */
76
+ export async function certsRecover(projectDir) {
77
+ const config = readAgentConfig(projectDir);
78
+ if (!config) {
79
+ console.error('No macf-agent.json found. Run `macf init` first.');
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+ const token = await generateToken(tokenSourceFromConfig(projectDir, config));
84
+ const client = getVariablesClient(config, token);
85
+ const passphrase = await promptPassphrase('Enter passphrase for CA key recovery: ');
86
+ if (!passphrase) {
87
+ console.error('Passphrase is required for recovery.');
88
+ process.exitCode = 1;
89
+ return;
90
+ }
91
+ // Per-project CA paths. mkdir with 0o700.
92
+ mkdirSync(caDir(config.project), { recursive: true, mode: 0o700 });
93
+ const caKeyP = caKeyPathFor(config.project);
94
+ console.log('Recovering CA key from registry...');
95
+ await recoverCAKey({
96
+ project: config.project,
97
+ passphrase,
98
+ keyPath: caKeyP,
99
+ client,
100
+ });
101
+ console.log(` CA key recovered to: ${caKeyP}`);
102
+ console.log('Recovery complete.');
103
+ }
104
+ /**
105
+ * macf certs rotate: regenerate agent cert with existing CA
106
+ */
107
+ export async function certsRotate(projectDir) {
108
+ const config = readAgentConfig(projectDir);
109
+ if (!config) {
110
+ console.error('No macf-agent.json found. Run `macf init` first.');
111
+ process.exitCode = 1;
112
+ return;
113
+ }
114
+ const caCertP = caCertPathFor(config.project);
115
+ const caKeyP = caKeyPathFor(config.project);
116
+ if (!existsSync(caCertP) || !existsSync(caKeyP)) {
117
+ console.error('CA cert or key not found. Run `macf certs init` or `macf certs recover` first.');
118
+ process.exitCode = 1;
119
+ return;
120
+ }
121
+ const ca = loadCA(caCertP, caKeyP);
122
+ const certP = agentCertPath(projectDir);
123
+ const keyP = agentKeyPath(projectDir);
124
+ console.log(`Rotating certificate for "${config.agent_name}"...`);
125
+ await generateAgentCert({
126
+ agentName: config.agent_name,
127
+ caCertPem: ca.certPem,
128
+ caKeyPem: ca.keyPem,
129
+ // Flow the advertised host into the cert SAN so TLS hostname
130
+ // verification succeeds when an off-box consumer (routing Action,
131
+ // sibling agent) connects over the network. macf#178 Gap 3.
132
+ ...(config.advertise_host !== undefined ? { advertiseHost: config.advertise_host } : {}),
133
+ certPath: certP,
134
+ keyPath: keyP,
135
+ });
136
+ console.log(` Cert: ${certP}`);
137
+ console.log(` Key: ${keyP}`);
138
+ console.log('Rotation complete.');
139
+ }
140
+ /**
141
+ * macf certs issue-routing-client: mint a CA-signed client cert with
142
+ * CN=routing-action for use by the macf-actions routing workflow
143
+ * (mTLS variant, macf-actions#8). The routing Action presents this
144
+ * cert when POSTing to each agent's /notify endpoint.
145
+ *
146
+ * Requires the CA key on disk — this command is local-only, never
147
+ * driven from the registry-encrypted backup. The resulting cert/key
148
+ * is meant to be pasted into the consumer repo's GHA secrets; the
149
+ * operator is expected to handle the paste securely (not commit it).
150
+ *
151
+ * If --out-dir is omitted, both PEMs are printed to stdout along with
152
+ * single-line base64 blobs for easy GHA-secret paste. If --out-dir
153
+ * is provided, files are written to disk at 0o600 / 0o644.
154
+ */
155
+ export async function issueRoutingClient(projectDir, opts = {}) {
156
+ const config = readAgentConfig(projectDir);
157
+ if (!config) {
158
+ console.error('No macf-agent.json found. Run `macf init` first.');
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ const validityDays = opts.validityDays ?? DEFAULT_VALIDITY_DAYS;
163
+ if (!Number.isInteger(validityDays) || validityDays < 1) {
164
+ console.error(`--validity-days must be a positive integer (got "${opts.validityDays}")`);
165
+ process.exitCode = 1;
166
+ return;
167
+ }
168
+ if (validityDays > VALIDITY_WARN_DAYS) {
169
+ console.warn(`Warning: validity of ${validityDays} days exceeds ${VALIDITY_WARN_DAYS} days. ` +
170
+ `Long-lived client certs increase blast radius if the key leaks; ` +
171
+ `consider a shorter rotation cadence.`);
172
+ }
173
+ const caCertP = caCertPathFor(config.project);
174
+ const caKeyP = caKeyPathFor(config.project);
175
+ if (!existsSync(caCertP) || !existsSync(caKeyP)) {
176
+ console.error('CA cert or key not found on disk. This command requires a local CA key — ' +
177
+ 'run `macf certs init` (first time) or `macf certs recover` (if CA lives in registry only).');
178
+ process.exitCode = 1;
179
+ return;
180
+ }
181
+ const ca = loadCA(caCertP, caKeyP);
182
+ // Collision guard: refuse if an existing agent is registered under
183
+ // the routing-client CN. Prevents accidental overlap with a real
184
+ // agent named `routing-action`.
185
+ const token = await generateToken(tokenSourceFromConfig(projectDir, config));
186
+ const registry = createRegistryFromConfig(config.registry, config.project, token);
187
+ const existing = await registry.get(ROUTING_CLIENT_CN);
188
+ if (existing !== null) {
189
+ console.error(`An agent named "${ROUTING_CLIENT_CN}" is already registered. ` +
190
+ `Rename or remove that agent before issuing the routing-client cert, or ` +
191
+ `coordinate CN separation via a follow-up issue.`);
192
+ process.exitCode = 1;
193
+ return;
194
+ }
195
+ console.log(`Issuing routing-client cert for project "${config.project}"...`);
196
+ console.log(` CN: ${ROUTING_CLIENT_CN}`);
197
+ console.log(` Validity: ${validityDays} days`);
198
+ const result = await generateClientCert({
199
+ commonName: ROUTING_CLIENT_CN,
200
+ validityDays,
201
+ caCertPem: ca.certPem,
202
+ caKeyPem: ca.keyPem,
203
+ });
204
+ if (opts.outDir) {
205
+ mkdirSync(opts.outDir, { recursive: true, mode: 0o700 });
206
+ const certOut = join(opts.outDir, 'routing-action-cert.pem');
207
+ const keyOut = join(opts.outDir, 'routing-action-key.pem');
208
+ writeFileSync(certOut, result.certPem, { mode: 0o644 });
209
+ writeFileSync(keyOut, result.keyPem, { mode: 0o600 });
210
+ console.log(` Cert written: ${certOut}`);
211
+ console.log(` Key written: ${keyOut}`);
212
+ console.log('');
213
+ console.log('GHA-secret paste format (for your consumer repo):');
214
+ console.log(' ROUTING_CLIENT_CERT = ' + Buffer.from(result.certPem).toString('base64'));
215
+ console.log(' ROUTING_CLIENT_KEY = ' + Buffer.from(result.keyPem).toString('base64'));
216
+ }
217
+ else {
218
+ console.log('');
219
+ console.log('─── routing-action cert (PEM) ───');
220
+ console.log(result.certPem);
221
+ console.log('─── routing-action key (PEM, KEEP SECRET) ───');
222
+ console.log(result.keyPem);
223
+ console.log('─── GHA-secret paste format ───');
224
+ console.log('ROUTING_CLIENT_CERT = ' + Buffer.from(result.certPem).toString('base64'));
225
+ console.log('ROUTING_CLIENT_KEY = ' + Buffer.from(result.keyPem).toString('base64'));
226
+ }
227
+ console.log('');
228
+ console.log('Next steps (see macf-actions#8):');
229
+ console.log(' 1. Paste ROUTING_CLIENT_CERT and ROUTING_CLIENT_KEY into your consumer repo\'s GHA secrets');
230
+ console.log(' 2. Upgrade the caller workflow to macf-actions @v2.x when available');
231
+ console.log(' 3. Remove the AGENT_SSH_KEY secret once mTLS transport is proven');
232
+ }
233
+ //# sourceMappingURL=certs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certs.js","sourceRoot":"","sources":["../../../src/cli/commands/certs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * One required permission entry from DR-019.
3
+ */
4
+ export interface RequiredPermission {
5
+ readonly name: string;
6
+ readonly level: 'read' | 'write';
7
+ readonly why: string;
8
+ }
9
+ /**
10
+ * DR-019 permission doctrine. Keep in sync with
11
+ * design/decisions/DR-019-app-permissions.md and
12
+ * templates/macf-app-manifest.json.
13
+ *
14
+ * Names here are GitHub's CANONICAL API names (as returned by
15
+ * `GET /app/installations/:id` in the `permissions` field), which
16
+ * differ from the App settings UI labels for some entries — notably
17
+ * Variables → `actions_variables`. We use canonical names everywhere
18
+ * to avoid false negatives (an installation with `actions_variables`
19
+ * would be flagged as missing `variables` if we used the UI label).
20
+ */
21
+ export declare const MACF_REQUIRED_PERMISSIONS: readonly RequiredPermission[];
22
+ export interface DoctorFinding {
23
+ /** Missing: the token has no entry at all for this permission. */
24
+ readonly missing: readonly RequiredPermission[];
25
+ /** Present but at a lower level than required (`read` where we want `write`). */
26
+ readonly insufficient: readonly {
27
+ readonly required: RequiredPermission;
28
+ readonly actual: string;
29
+ }[];
30
+ }
31
+ /**
32
+ * Pure comparison: given the actual permission map from a token response,
33
+ * return what's missing or insufficient against MACF_REQUIRED_PERMISSIONS.
34
+ */
35
+ export declare function diffPermissions(actual: Readonly<Record<string, string>>): DoctorFinding;
36
+ /**
37
+ * Symbol + label for the output table. Exported so tests can assert on it.
38
+ */
39
+ export declare function formatPermissionRow(req: RequiredPermission, actual: string | undefined): string;
40
+ /**
41
+ * Result of the sandbox-filesystem check (macf#202). PASS iff the
42
+ * workspace's `.claude/settings.json` has `/proc/self/fd` in
43
+ * `sandbox.filesystem.allowRead`. FAIL if absent, or if reading the
44
+ * file threw (malformed JSON → we don't silently report PASS).
45
+ *
46
+ * Note: an earlier CLI version wrote `/proc/self/fd/**` (glob) which
47
+ * the sandbox treated as a literal — silently didn't match; macf#208
48
+ * corrected the pattern to bare `/proc/self/fd`.
49
+ */
50
+ export interface SandboxFdCheck {
51
+ readonly status: 'PASS' | 'FAIL';
52
+ /** Human-readable diagnostic — e.g. JSON parse error message. Empty on PASS. */
53
+ readonly detail: string;
54
+ }
55
+ /**
56
+ * Pure check: does this workspace's `.claude/settings.json` contain
57
+ * the `/proc/self/fd` sandbox pattern? See macf#200 for why this
58
+ * matters (without it every Bash tool call fails on the harness fd),
59
+ * and macf#208 for why the pattern is bare (not a glob).
60
+ *
61
+ * Uses `getSandboxAllowRead` from `settings-writer.ts` so the JSON-
62
+ * read + deep-narrow logic lives in one place. Malformed JSON
63
+ * surfaces as a FAIL with the parse error in `detail` — operator
64
+ * still needs to see what broke.
65
+ */
66
+ export declare function checkSandboxFdAllowRead(workspaceDir: string): SandboxFdCheck;
67
+ /**
68
+ * Format a non-leaking error message when `gh token generate --jwt` returns
69
+ * output that doesn't look like a JWT. Shows only the first 6 characters
70
+ * plus length — enough to distinguish empty / error-message / binary-garbage
71
+ * / genuinely-wrong-prefix, without exposing credential material if the
72
+ * branch fires on a genuinely-valid JWT due to a locale/whitespace/plugin
73
+ * edge case. See #86. Exported for unit tests.
74
+ */
75
+ export declare function describeNonJwtOutput(jwt: string): string;
76
+ /**
77
+ * Fetch the installation's GRANTED permissions by querying
78
+ * `GET /app/installations/:id` with an App JWT. We do NOT use the
79
+ * install-token response's `permissions` field here — it doesn't
80
+ * surface all granted permissions (verified empirically: an App with
81
+ * `actions_variables: write` may report an incomplete set in the
82
+ * install-token response but the full set via JWT query). See
83
+ * discussion on issue #74 for the evidence.
84
+ */
85
+ export declare function fetchInstallationPermissions(appId: string, installId: string, keyPath: string): Promise<Record<string, string>>;
86
+ /**
87
+ * Main entry for `macf doctor`. Returns the shell exit code: 0 if all
88
+ * required permissions are present, 1 if any are missing or insufficient.
89
+ */
90
+ export declare function runDoctor(projectDir: string): Promise<number>;
91
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,kBAAkB,EAQlE,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAChD,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,SAAS;QAC9B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;QACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,EAAE,CAAC;CACL;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,aAAa,CAgBvF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,EACvB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,CAWR;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,CAc5E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA6CjC;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsEnE"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * macf doctor — verify the workspace's bot token satisfies the MACF App
3
+ * permission doctrine (DR-019).
4
+ *
5
+ * GitHub's installation-token response body includes the permissions
6
+ * granted to the installation, so we don't need to probe individual
7
+ * endpoints: one `gh token generate` (without --token-only) gives us
8
+ * the full permission map. Compare against the required set; print a
9
+ * formatted checklist; exit 0 if satisfied, 1 if not.
10
+ *
11
+ * This is the automated counterpart to DR-019's manual verification
12
+ * section. Run at onboarding time or whenever routing breaks for a
13
+ * reason that smells like a missing permission (401 on a specific
14
+ * endpoint while others work — see coordination.md Token & Git Hygiene
15
+ * for the attribution-trap class this prevents).
16
+ */
17
+ import { execFileSync } from 'node:child_process';
18
+ import { readAgentConfig, tokenSourceFromConfig } from '../config.js';
19
+ import { getSandboxAllowRead, SANDBOX_FD_READ_PATTERN } from '../settings-writer.js';
20
+ /**
21
+ * DR-019 permission doctrine. Keep in sync with
22
+ * design/decisions/DR-019-app-permissions.md and
23
+ * templates/macf-app-manifest.json.
24
+ *
25
+ * Names here are GitHub's CANONICAL API names (as returned by
26
+ * `GET /app/installations/:id` in the `permissions` field), which
27
+ * differ from the App settings UI labels for some entries — notably
28
+ * Variables → `actions_variables`. We use canonical names everywhere
29
+ * to avoid false negatives (an installation with `actions_variables`
30
+ * would be flagged as missing `variables` if we used the UI label).
31
+ */
32
+ export const MACF_REQUIRED_PERMISSIONS = [
33
+ { name: 'metadata', level: 'read', why: 'Mandatory by GitHub — cannot be omitted' },
34
+ { name: 'contents', level: 'write', why: 'Push commits, PRs to feature branches' },
35
+ { name: 'issues', level: 'write', why: 'Comment, label, edit issues — primary coordination surface' },
36
+ { name: 'pull_requests', level: 'write', why: 'Create/merge PRs, submit reviews' },
37
+ { name: 'actions_variables', level: 'write', why: 'Agent registry lives in repo/org/user variables (UI label: Variables)' },
38
+ { name: 'workflows', level: 'write', why: 'macf repo-init writes .github/workflows/' },
39
+ { name: 'actions', level: 'read', why: 'gh run list / view --log-failed for self-debug' },
40
+ ];
41
+ /**
42
+ * Pure comparison: given the actual permission map from a token response,
43
+ * return what's missing or insufficient against MACF_REQUIRED_PERMISSIONS.
44
+ */
45
+ export function diffPermissions(actual) {
46
+ const missing = [];
47
+ const insufficient = [];
48
+ for (const req of MACF_REQUIRED_PERMISSIONS) {
49
+ const actualLevel = actual[req.name];
50
+ if (!actualLevel) {
51
+ missing.push(req);
52
+ continue;
53
+ }
54
+ // 'write' required but only 'read' granted is a gap; the reverse
55
+ // ('read' required with 'write' granted) is fine — user exceeds.
56
+ if (req.level === 'write' && actualLevel === 'read') {
57
+ insufficient.push({ required: req, actual: actualLevel });
58
+ }
59
+ }
60
+ return { missing, insufficient };
61
+ }
62
+ /**
63
+ * Symbol + label for the output table. Exported so tests can assert on it.
64
+ */
65
+ export function formatPermissionRow(req, actual) {
66
+ const name = req.name.padEnd(15);
67
+ const required = `${req.level}`.padEnd(6);
68
+ if (!actual) {
69
+ return `✗ ${name} required=${required} actual=MISSING — ${req.why}`;
70
+ }
71
+ const actualStr = actual.padEnd(6);
72
+ if (req.level === 'write' && actual === 'read') {
73
+ return `⚠ ${name} required=${required} actual=${actualStr} — need write, have read`;
74
+ }
75
+ return `✓ ${name} required=${required} actual=${actualStr}`;
76
+ }
77
+ /**
78
+ * Pure check: does this workspace's `.claude/settings.json` contain
79
+ * the `/proc/self/fd` sandbox pattern? See macf#200 for why this
80
+ * matters (without it every Bash tool call fails on the harness fd),
81
+ * and macf#208 for why the pattern is bare (not a glob).
82
+ *
83
+ * Uses `getSandboxAllowRead` from `settings-writer.ts` so the JSON-
84
+ * read + deep-narrow logic lives in one place. Malformed JSON
85
+ * surfaces as a FAIL with the parse error in `detail` — operator
86
+ * still needs to see what broke.
87
+ */
88
+ export function checkSandboxFdAllowRead(workspaceDir) {
89
+ let allowRead;
90
+ try {
91
+ allowRead = getSandboxAllowRead(workspaceDir);
92
+ }
93
+ catch (err) {
94
+ return { status: 'FAIL', detail: err instanceof Error ? err.message : String(err) };
95
+ }
96
+ if (allowRead.includes(SANDBOX_FD_READ_PATTERN)) {
97
+ return { status: 'PASS', detail: '' };
98
+ }
99
+ return {
100
+ status: 'FAIL',
101
+ detail: `allowRead does not contain ${SANDBOX_FD_READ_PATTERN} — run \`macf update\` to refresh`,
102
+ };
103
+ }
104
+ /**
105
+ * Format a non-leaking error message when `gh token generate --jwt` returns
106
+ * output that doesn't look like a JWT. Shows only the first 6 characters
107
+ * plus length — enough to distinguish empty / error-message / binary-garbage
108
+ * / genuinely-wrong-prefix, without exposing credential material if the
109
+ * branch fires on a genuinely-valid JWT due to a locale/whitespace/plugin
110
+ * edge case. See #86. Exported for unit tests.
111
+ */
112
+ export function describeNonJwtOutput(jwt) {
113
+ const safePrefix = jwt.length > 0 ? jwt.slice(0, 6) : '(empty)';
114
+ return (`gh token generate --jwt returned unexpected output ` +
115
+ `(prefix='${safePrefix}', length=${jwt.length})`);
116
+ }
117
+ /**
118
+ * Fetch the installation's GRANTED permissions by querying
119
+ * `GET /app/installations/:id` with an App JWT. We do NOT use the
120
+ * install-token response's `permissions` field here — it doesn't
121
+ * surface all granted permissions (verified empirically: an App with
122
+ * `actions_variables: write` may report an incomplete set in the
123
+ * install-token response but the full set via JWT query). See
124
+ * discussion on issue #74 for the evidence.
125
+ */
126
+ export async function fetchInstallationPermissions(appId, installId, keyPath) {
127
+ // Get a JWT signed with the App's private key. `gh token generate --jwt`
128
+ // does the RS256 signing for us, avoiding a Node crypto reimplementation.
129
+ let jwt;
130
+ try {
131
+ jwt = execFileSync('gh', [
132
+ 'token', 'generate',
133
+ '--app-id', appId,
134
+ '--key', keyPath,
135
+ '--jwt',
136
+ '--token-only',
137
+ ], {
138
+ encoding: 'utf-8',
139
+ stdio: ['ignore', 'pipe', 'pipe'],
140
+ }).trim();
141
+ }
142
+ catch (err) {
143
+ const msg = err instanceof Error ? err.message : String(err);
144
+ throw new Error(`gh token generate --jwt failed: ${msg}. ` +
145
+ `See coordination.md Token & Git Hygiene for diagnostics.`, { cause: err });
146
+ }
147
+ if (!jwt.startsWith('eyJ')) {
148
+ throw new Error(describeNonJwtOutput(jwt));
149
+ }
150
+ const response = await fetch(`https://api.github.com/app/installations/${installId}`, {
151
+ headers: {
152
+ Authorization: `Bearer ${jwt}`,
153
+ Accept: 'application/vnd.github+json',
154
+ 'X-GitHub-Api-Version': '2022-11-28',
155
+ },
156
+ });
157
+ if (!response.ok) {
158
+ const body = await response.text().catch(() => '<no body>');
159
+ throw new Error(`GET /app/installations/${installId} returned ${response.status}: ${body.slice(0, 200)}`);
160
+ }
161
+ const parsed = (await response.json());
162
+ if (!parsed.permissions || typeof parsed.permissions !== 'object') {
163
+ throw new Error('/app/installations/:id response missing `permissions` field');
164
+ }
165
+ return parsed.permissions;
166
+ }
167
+ /**
168
+ * Main entry for `macf doctor`. Returns the shell exit code: 0 if all
169
+ * required permissions are present, 1 if any are missing or insufficient.
170
+ */
171
+ export async function runDoctor(projectDir) {
172
+ const config = readAgentConfig(projectDir);
173
+ if (!config) {
174
+ console.error('No macf-agent.json found. Run `macf init` first.');
175
+ return 1;
176
+ }
177
+ const source = tokenSourceFromConfig(projectDir, config);
178
+ let permissions;
179
+ try {
180
+ permissions = await fetchInstallationPermissions(source.appId, source.installId, source.keyPath);
181
+ }
182
+ catch (err) {
183
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
184
+ return 1;
185
+ }
186
+ const finding = diffPermissions(permissions);
187
+ console.log('MACF doctor report');
188
+ console.log('──────────────────────────────────────────────────────────────');
189
+ for (const req of MACF_REQUIRED_PERMISSIONS) {
190
+ console.log(` ${formatPermissionRow(req, permissions[req.name])}`);
191
+ }
192
+ console.log('');
193
+ const totalRequired = MACF_REQUIRED_PERMISSIONS.length;
194
+ const satisfied = totalRequired - finding.missing.length - finding.insufficient.length;
195
+ const status = finding.missing.length === 0 && finding.insufficient.length === 0
196
+ ? '✓ all required permissions present'
197
+ : `✗ ${finding.missing.length + finding.insufficient.length} of ${totalRequired} required permissions missing or insufficient`;
198
+ console.log(` ${status} (${satisfied}/${totalRequired} satisfied)`);
199
+ if (finding.missing.length > 0) {
200
+ console.log('');
201
+ console.log('Missing:');
202
+ for (const req of finding.missing) {
203
+ console.log(` - ${req.name}: ${req.level} — ${req.why}`);
204
+ }
205
+ }
206
+ if (finding.insufficient.length > 0) {
207
+ console.log('');
208
+ console.log('Insufficient:');
209
+ for (const { required, actual } of finding.insufficient) {
210
+ console.log(` - ${required.name}: have ${actual}, need ${required.level} — ${required.why}`);
211
+ }
212
+ }
213
+ if (finding.missing.length > 0 || finding.insufficient.length > 0) {
214
+ console.log('');
215
+ console.log('See design/decisions/DR-019-app-permissions.md for the full doctrine,');
216
+ console.log('and GitHub → Settings → Developer settings → GitHub Apps → <your App> → Permissions');
217
+ console.log('to update the App. Users with the App installed must accept the new permissions.');
218
+ }
219
+ console.log('');
220
+ console.log('Sandbox filesystem (macf#200)');
221
+ console.log('──────────────────────────────────────────────────────────────');
222
+ const sandboxCheck = checkSandboxFdAllowRead(projectDir);
223
+ if (sandboxCheck.status === 'PASS') {
224
+ console.log(` ✓ sandbox.filesystem.allowRead contains ${SANDBOX_FD_READ_PATTERN} [PASS]`);
225
+ }
226
+ else {
227
+ console.log(` ✗ sandbox.filesystem.allowRead missing ${SANDBOX_FD_READ_PATTERN} [FAIL — run \`macf update\` to fix]`);
228
+ if (sandboxCheck.detail)
229
+ console.log(` ${sandboxCheck.detail}`);
230
+ }
231
+ const permissionsFailed = finding.missing.length > 0 || finding.insufficient.length > 0;
232
+ const sandboxFailed = sandboxCheck.status === 'FAIL';
233
+ return permissionsFailed || sandboxFailed ? 1 : 0;
234
+ }
235
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export interface InitOptions {
2
+ readonly project: string;
3
+ readonly role: string;
4
+ readonly name?: string;
5
+ readonly type?: string;
6
+ readonly appId: string;
7
+ readonly installId: string;
8
+ readonly keyPath: string;
9
+ readonly registryType?: string;
10
+ readonly registryOrg?: string;
11
+ readonly registryUser?: string;
12
+ readonly registryRepo?: string;
13
+ /**
14
+ * Host the channel server advertises to the registry + includes in
15
+ * its mTLS cert SAN. When unset, launcher falls back to 127.0.0.1
16
+ * (matches plugin default). Operators routing to agents over the
17
+ * network (Tailscale IP / DNS) must set this. See macf#178.
18
+ */
19
+ readonly advertiseHost?: string;
20
+ /**
21
+ * Tmux session + (optional) window for the on-notify wake path
22
+ * (macf#185). When set, the channel server's onNotify shells out
23
+ * to tmux-send-to-claude.sh to inject the notification prompt
24
+ * into a running Claude TUI. When unset, the server auto-detects
25
+ * from $TMUX if launched inside a tmux pane.
26
+ */
27
+ readonly tmuxSession?: string;
28
+ readonly tmuxWindow?: string;
29
+ readonly cliVersion?: string;
30
+ readonly pluginVersion?: string;
31
+ readonly actionsVersion?: string;
32
+ }
33
+ /**
34
+ * Set up a project directory for an agent.
35
+ */
36
+ export declare function initAgent(projectDir: string, opts: InitOptions): Promise<void>;
37
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AA4GD;;GAEG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0JpF"}