polygram 0.38.7 → 0.39.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,74 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Builds the single self-contained Codex hook bundle from the checked-in
5
+ // sources. The build is a pure function of those sources, so `--check` is the
6
+ // drift gate: a bundle that no longer regenerates is never installed.
7
+
8
+ const { createHash } = require('node:crypto');
9
+ const { readFileSync, writeFileSync } = require('node:fs');
10
+
11
+ const {
12
+ HOOK_BUNDLE_PATH,
13
+ HOOK_BUNDLE_SOURCES,
14
+ buildHookBundle,
15
+ } = require('../lib/codex/hook-bundle');
16
+
17
+ const USAGE = 'usage: build-codex-hook-bundle [--check] [--out <path>]';
18
+
19
+ function parseArgs(argv) {
20
+ const options = { check: false, out: HOOK_BUNDLE_PATH };
21
+ for (let index = 0; index < argv.length; index += 1) {
22
+ const argument = argv[index];
23
+ if (argument === '--check') {
24
+ options.check = true;
25
+ } else if (argument === '--out') {
26
+ index += 1;
27
+ options.out = argv[index];
28
+ if (typeof options.out !== 'string' || options.out.length === 0) {
29
+ throw new Error(USAGE);
30
+ }
31
+ } else {
32
+ throw new Error(`${USAGE}\nunknown argument ${argument}`);
33
+ }
34
+ }
35
+ return options;
36
+ }
37
+
38
+ function main(argv) {
39
+ const options = parseArgs(argv);
40
+ const bundle = buildHookBundle();
41
+ const sha256 = createHash('sha256').update(bundle).digest('hex');
42
+
43
+ if (options.check) {
44
+ let current = null;
45
+ try {
46
+ current = readFileSync(options.out, 'utf8');
47
+ } catch {
48
+ process.stderr.write(`missing bundle at ${options.out}\n`);
49
+ return 1;
50
+ }
51
+ if (current !== bundle) {
52
+ process.stderr.write(
53
+ `bundle at ${options.out} is not what the sources build; `
54
+ + 'rebuild it in the same change as the sources\n',
55
+ );
56
+ return 1;
57
+ }
58
+ process.stdout.write(`ok ${sha256}\n`);
59
+ return 0;
60
+ }
61
+
62
+ writeFileSync(options.out, bundle, { mode: 0o644 });
63
+ process.stdout.write(
64
+ `${options.out}\nsources ${HOOK_BUNDLE_SOURCES.join(' ')}\nsha256 ${sha256}\n`,
65
+ );
66
+ return 0;
67
+ }
68
+
69
+ try {
70
+ process.exitCode = main(process.argv.slice(2));
71
+ } catch (error) {
72
+ process.stderr.write(`${error.message}\n`);
73
+ process.exitCode = 1;
74
+ }
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Operator entry point for the protected Codex hook artifact tree. It is run
5
+ // by the account that owns the tree — never by the service account, which must
6
+ // not be able to write anything it executes. The closure it installs comes
7
+ // from the shipped build output; there is no way to hand it a body.
8
+
9
+ const {
10
+ attestHookArtifactVersion,
11
+ installHookArtifactVersion,
12
+ listHookArtifactVersions,
13
+ quarantineHookArtifactVersion,
14
+ } = require('../lib/codex/hook-artifacts');
15
+
16
+ const USAGE = [
17
+ 'usage: polygram-codex-hook-artifacts <command> [options]',
18
+ '',
19
+ ' install --artifact-root <dir> --version <v> --runtime-root <dir>',
20
+ ' --runtime-id <id> --runtime-sha256 <hex>',
21
+ ' --operator-uid <uid> --service-uid <uid>',
22
+ ' attest --artifact-root <dir> --version <v> --runtime-root <dir>',
23
+ ' --runtime-id <id> --runtime-sha256 <hex>',
24
+ ' --operator-uid <uid> --service-uid <uid>',
25
+ ' list --artifact-root <dir>',
26
+ ' quarantine --artifact-root <dir> --version <v> --runtime-root <dir>',
27
+ ' --runtime-id <id> --runtime-sha256 <hex>',
28
+ ' --operator-uid <uid> --service-uid <uid> --referenced <v1,v2>',
29
+ ].join('\n');
30
+
31
+ const FLAGS = new Map([
32
+ ['--artifact-root', 'artifactRoot'],
33
+ ['--version', 'version'],
34
+ ['--runtime-root', 'runtimeRoot'],
35
+ ['--runtime-id', 'runtimeId'],
36
+ ['--runtime-sha256', 'runtimeSha256'],
37
+ ['--operator-uid', 'operatorUid'],
38
+ ['--service-uid', 'serviceUid'],
39
+ ['--referenced', 'referenced'],
40
+ ]);
41
+
42
+ function parseArgs(argv) {
43
+ const [command, ...rest] = argv;
44
+ if (!['install', 'attest', 'list', 'quarantine'].includes(command)) {
45
+ throw new Error(USAGE);
46
+ }
47
+ const options = { command };
48
+ for (let index = 0; index < rest.length; index += 2) {
49
+ const name = FLAGS.get(rest[index]);
50
+ const value = rest[index + 1];
51
+ if (!name || typeof value !== 'string') {
52
+ throw new Error(`${USAGE}\n\nunknown or incomplete option ${rest[index]}`);
53
+ }
54
+ options[name] = value;
55
+ }
56
+ return options;
57
+ }
58
+
59
+ function uid(value, flag) {
60
+ const parsed = Number(value);
61
+ if (!Number.isInteger(parsed) || parsed < 0) {
62
+ throw new Error(`${flag} must be the numeric uid of that account`);
63
+ }
64
+ return parsed;
65
+ }
66
+
67
+ function accounts(options) {
68
+ return {
69
+ operatorUid: uid(options.operatorUid, '--operator-uid'),
70
+ serviceUid: uid(options.serviceUid, '--service-uid'),
71
+ };
72
+ }
73
+
74
+ function run(options) {
75
+ switch (options.command) {
76
+ case 'install':
77
+ if (typeof options.runtimeSha256 !== 'string') {
78
+ throw new Error(
79
+ 'pass --runtime-sha256 with the expected digest of the protected '
80
+ + 'runtime binary',
81
+ );
82
+ }
83
+ return installHookArtifactVersion({
84
+ artifactRoot: options.artifactRoot,
85
+ version: options.version,
86
+ runtimeRoot: options.runtimeRoot,
87
+ runtimeId: options.runtimeId,
88
+ expectedRuntimeSha256: options.runtimeSha256,
89
+ ...accounts(options),
90
+ });
91
+ case 'attest':
92
+ return attestHookArtifactVersion({
93
+ artifactRoot: options.artifactRoot,
94
+ version: options.version,
95
+ runtimeRoot: options.runtimeRoot,
96
+ runtimeId: options.runtimeId,
97
+ runtimeSha256: options.runtimeSha256,
98
+ ...accounts(options),
99
+ });
100
+ case 'list':
101
+ return listHookArtifactVersions({ artifactRoot: options.artifactRoot });
102
+ case 'quarantine':
103
+ if (typeof options.referenced !== 'string') {
104
+ throw new Error(
105
+ 'pass --referenced with every version still referenced by a live '
106
+ + "session, or --referenced '' when none is",
107
+ );
108
+ }
109
+ return quarantineHookArtifactVersion({
110
+ artifactRoot: options.artifactRoot,
111
+ version: options.version,
112
+ runtimeRoot: options.runtimeRoot,
113
+ runtimeId: options.runtimeId,
114
+ runtimeSha256: options.runtimeSha256,
115
+ referencedVersions: options.referenced
116
+ .split(',')
117
+ .map((entry) => entry.trim())
118
+ .filter(Boolean),
119
+ ...accounts(options),
120
+ });
121
+ default:
122
+ throw new Error(USAGE);
123
+ }
124
+ }
125
+
126
+ try {
127
+ const result = run(parseArgs(process.argv.slice(2)));
128
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
129
+ } catch (error) {
130
+ process.stderr.write(
131
+ `${error.code ? `${error.code}: ` : ''}${error.message}\n${
132
+ error.action ? `${error.action}\n` : ''
133
+ }`,
134
+ );
135
+ process.exitCode = 1;
136
+ }