@t275005746/gse 0.1.0 → 0.1.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/.github/ISSUE_TEMPLATE/bug_report.yml +42 -42
- package/.github/ISSUE_TEMPLATE/change_request.yml +50 -50
- package/.github/ISSUE_TEMPLATE/config.yml +5 -5
- package/.github/PULL_REQUEST_TEMPLATE.md +38 -38
- package/.github/workflows/validate-gse.yml +33 -33
- package/.gse/README.md +18 -18
- package/.gse/gse-development-protocol.md +50 -50
- package/.gse/project-profile.md +29 -29
- package/.gse/quality-gates.md +25 -25
- package/.gse/releases/public-registry-publication-npm.md +49 -0
- package/.gse/releases/public-release-owner-required.md +65 -65
- package/.gse/releases/public-security-contact-owner-required.md +45 -45
- package/.gse/state.json +3 -4
- package/CHANGELOG.md +24 -24
- package/CONTRIBUTING.md +64 -64
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/SECURITY.md +41 -41
- package/SUPPORT.md +38 -38
- package/assets/marketplace/README.md +7 -7
- package/assets/marketplace/gse-listing.json +75 -75
- package/assets/templates/acceptance-execution-packet.md +73 -73
- package/assets/templates/adr.md +14 -14
- package/assets/templates/change-brief.md +16 -16
- package/assets/templates/design.md +18 -18
- package/assets/templates/dispatch-packet.md +104 -104
- package/assets/templates/evidence.md +14 -14
- package/assets/templates/execution-quality-pack.md +65 -65
- package/assets/templates/goal-map.md +21 -21
- package/assets/templates/host-adapter.md +48 -48
- package/assets/templates/host-ui-invocation-record.md +42 -42
- package/assets/templates/incident-review.md +60 -60
- package/assets/templates/public-channel-publication-record.md +49 -49
- package/assets/templates/public-ci-run-record.md +53 -53
- package/assets/templates/public-release-record.md +65 -65
- package/assets/templates/public-repository-settings-record.md +59 -59
- package/assets/templates/public-security-contact-record.md +45 -45
- package/assets/templates/release-trust-record.md +32 -32
- package/assets/templates/review.md +18 -18
- package/assets/templates/spec.md +16 -16
- package/assets/templates/target-adoption-evidence.md +29 -29
- package/assets/templates/tasks.md +17 -17
- package/assets/templates/update-release-acceptance-record.md +58 -58
- package/examples/README.md +22 -22
- package/examples/agent-runtime-host/.claude/gse-adapter.md +6 -6
- package/examples/agent-runtime-host/.codex/gse-adapter.md +7 -7
- package/examples/agent-runtime-host/.gse/goal-map.md +7 -7
- package/examples/agent-runtime-host/.gse/project-profile.md +27 -27
- package/examples/agent-runtime-host/.gse/tooling.md +5 -5
- package/examples/agent-runtime-host/.mcp.json +9 -9
- package/examples/agent-runtime-host/AGENTS.md +5 -5
- package/examples/agent-runtime-host/README.md +10 -10
- package/examples/agent-runtime-host/docs/model-routing.md +5 -5
- package/examples/cli-tool/.gse/project-profile.md +21 -21
- package/examples/cli-tool/AGENTS.md +5 -5
- package/examples/cli-tool/README.md +12 -12
- package/examples/cli-tool/package.json +21 -21
- package/examples/small-app/.env.example +2 -2
- package/examples/small-app/.github/workflows/ci.yml +8 -8
- package/examples/small-app/AGENTS.md +5 -5
- package/examples/small-app/README.md +12 -12
- package/examples/small-app/package.json +26 -26
- package/examples/small-app/playwright.config.ts +4 -4
- package/package.json +53 -53
- package/references/adoption-recipes.md +171 -171
- package/references/agent-roles.md +49 -49
- package/references/architecture-health.md +101 -101
- package/references/benchmark-audit.md +73 -73
- package/references/community-channels.md +46 -46
- package/references/compatibility.md +70 -70
- package/references/design-basis.md +38 -38
- package/references/domain-model.md +129 -129
- package/references/domain-quality-gates.md +75 -75
- package/references/drift-audit.md +81 -81
- package/references/evidence-taxonomy.md +123 -123
- package/references/file-ownership.md +107 -107
- package/references/final-readiness.md +84 -84
- package/references/forward-test.md +133 -133
- package/references/goal-map.md +36 -36
- package/references/host-adapters.md +119 -119
- package/references/learning-system.md +35 -35
- package/references/marketplace-discovery.md +46 -46
- package/references/model-routing.md +103 -103
- package/references/open-source-defaults.md +39 -39
- package/references/operating-model.md +52 -52
- package/references/packaging.md +277 -277
- package/references/project-agent-workspace.md +89 -89
- package/references/project-bootstrap.md +122 -122
- package/references/project-profile.md +57 -57
- package/references/public-release.md +174 -174
- package/references/quality-gates.md +100 -100
- package/references/recovery.md +176 -176
- package/references/release-trust.md +43 -43
- package/references/release.md +126 -126
- package/references/review.md +141 -141
- package/references/router.md +90 -90
- package/references/spec-workflow.md +66 -66
- package/references/task-levels.md +81 -81
- package/references/tool-adapters.md +73 -73
- package/scripts/audit-acceptance-execution-packet.mjs +133 -133
- package/scripts/audit-adoption-recipes.mjs +99 -99
- package/scripts/audit-change-lifecycle.mjs +77 -77
- package/scripts/audit-change-system.mjs +134 -134
- package/scripts/audit-ci-readiness.mjs +107 -107
- package/scripts/audit-close-gate.mjs +323 -323
- package/scripts/audit-command-adapters.mjs +91 -91
- package/scripts/audit-command-execution.mjs +210 -210
- package/scripts/audit-compatibility.mjs +149 -149
- package/scripts/audit-completion-readiness.mjs +292 -292
- package/scripts/audit-distribution.mjs +251 -251
- package/scripts/audit-domain-quality-gates.mjs +108 -108
- package/scripts/audit-evidence-placeholders.mjs +126 -126
- package/scripts/audit-final-readiness-promotion.mjs +255 -255
- package/scripts/audit-final-readiness.mjs +226 -226
- package/scripts/audit-fixtures.mjs +154 -154
- package/scripts/audit-fresh-session-readiness.mjs +177 -177
- package/scripts/audit-host-runtime-evidence-handoff.mjs +159 -159
- package/scripts/audit-host-runtime-invocation-drill.mjs +240 -240
- package/scripts/audit-host-runtime-invocations.mjs +254 -254
- package/scripts/audit-host-ui-invocation.mjs +132 -132
- package/scripts/audit-marketplace-discovery.mjs +122 -122
- package/scripts/audit-npm-package-metadata.mjs +155 -155
- package/scripts/audit-npm-publish-dry-run.mjs +191 -169
- package/scripts/audit-npm-tarball-install.mjs +191 -191
- package/scripts/audit-open-source-defaults.mjs +92 -92
- package/scripts/audit-open-source-readiness.mjs +97 -97
- package/scripts/audit-project.mjs +138 -138
- package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -203
- package/scripts/audit-public-acceptance-readiness.mjs +224 -224
- package/scripts/audit-public-channel-publication.mjs +248 -248
- package/scripts/audit-public-ci-run.mjs +184 -184
- package/scripts/audit-public-collaboration-templates.mjs +98 -98
- package/scripts/audit-public-external-gate-probe.mjs +206 -206
- package/scripts/audit-public-release-decision.mjs +201 -201
- package/scripts/audit-public-release-metadata.mjs +176 -176
- package/scripts/audit-public-repository-settings.mjs +237 -237
- package/scripts/audit-public-security-contact.mjs +171 -171
- package/scripts/audit-readme-docs.mjs +6 -4
- package/scripts/audit-recovery-readiness.mjs +98 -98
- package/scripts/audit-release-readiness.mjs +106 -106
- package/scripts/audit-release-trust.mjs +62 -62
- package/scripts/audit-remote-distribution.mjs +266 -266
- package/scripts/audit-roadmap-consistency.mjs +235 -235
- package/scripts/audit-signing.mjs +147 -147
- package/scripts/audit-state-freshness.mjs +14 -9
- package/scripts/audit-target-adoption-evidence.mjs +117 -117
- package/scripts/audit-target-project.mjs +507 -507
- package/scripts/audit-update-release-acceptance.mjs +136 -136
- package/scripts/audit-v1-target-validation.mjs +269 -269
- package/scripts/audit-validation-profiles.mjs +125 -125
- package/scripts/close-change.mjs +116 -116
- package/scripts/discover-project-profile.mjs +307 -307
- package/scripts/generate-command-adapter.mjs +231 -231
- package/scripts/generate-final-acceptance-packet.mjs +181 -181
- package/scripts/generate-final-form-progress-report.mjs +205 -205
- package/scripts/generate-host-runtime-evidence-handoff.mjs +206 -206
- package/scripts/generate-owner-external-gate-kit.mjs +295 -295
- package/scripts/generate-public-acceptance-handoff.mjs +168 -168
- package/scripts/generate-public-release-checklist.mjs +207 -207
- package/scripts/generate-release-bundle.mjs +505 -505
- package/scripts/generate-release-owner-action-plan.mjs +172 -172
- package/scripts/generate-release-status-manifest.mjs +200 -200
- package/scripts/generate-session-prompt.mjs +188 -188
- package/scripts/gse.mjs +67 -67
- package/scripts/init-change.mjs +265 -265
- package/scripts/init-project.mjs +785 -785
- package/scripts/install-gse.mjs +234 -234
- package/scripts/lib/evidence-placeholders.mjs +28 -28
- package/scripts/package-gse.mjs +174 -174
- package/scripts/probe-public-external-gates.mjs +167 -167
- package/scripts/record-host-invocation.mjs +151 -151
- package/scripts/record-public-channel-publication.mjs +178 -178
- package/scripts/record-public-ci-run.mjs +180 -180
- package/scripts/record-public-release.mjs +175 -175
- package/scripts/record-public-repository-settings.mjs +209 -209
- package/scripts/record-public-security-contact.mjs +157 -157
- package/scripts/sign-gse-package.mjs +83 -83
- package/scripts/update-project-state.mjs +223 -223
- package/scripts/verify-gse-package.mjs +85 -85
|
@@ -1,206 +1,206 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from 'node:fs'
|
|
3
|
-
import http from 'node:http'
|
|
4
|
-
import os from 'node:os'
|
|
5
|
-
import path from 'node:path'
|
|
6
|
-
import { spawn, spawnSync } from 'node:child_process'
|
|
7
|
-
|
|
8
|
-
const args = process.argv.slice(2)
|
|
9
|
-
|
|
10
|
-
function readArg(name, fallback = null) {
|
|
11
|
-
const index = args.indexOf(name)
|
|
12
|
-
if (index === -1) return fallback
|
|
13
|
-
return args[index + 1] ?? fallback
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
17
|
-
const jsonOnly = args.includes('--json')
|
|
18
|
-
|
|
19
|
-
function read(relativePath) {
|
|
20
|
-
const fullPath = path.join(root, relativePath)
|
|
21
|
-
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8') : ''
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function exists(relativePath) {
|
|
25
|
-
return fs.existsSync(path.join(root, relativePath))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function run(command, commandArgs) {
|
|
29
|
-
const result = spawnSync(command, commandArgs, {
|
|
30
|
-
cwd: root,
|
|
31
|
-
encoding: 'utf8',
|
|
32
|
-
windowsHide: true,
|
|
33
|
-
})
|
|
34
|
-
return {
|
|
35
|
-
status: result.status ?? 1,
|
|
36
|
-
stdout: (result.stdout ?? '').trim(),
|
|
37
|
-
stderr: (result.stderr ?? '').trim(),
|
|
38
|
-
command: [command, ...commandArgs].join(' '),
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function runAsync(command, commandArgs) {
|
|
43
|
-
return new Promise((resolve) => {
|
|
44
|
-
const child = spawn(command, commandArgs, {
|
|
45
|
-
cwd: root,
|
|
46
|
-
windowsHide: true,
|
|
47
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
48
|
-
})
|
|
49
|
-
let stdout = ''
|
|
50
|
-
let stderr = ''
|
|
51
|
-
child.stdout.setEncoding('utf8')
|
|
52
|
-
child.stderr.setEncoding('utf8')
|
|
53
|
-
child.stdout.on('data', (chunk) => {
|
|
54
|
-
stdout += chunk
|
|
55
|
-
})
|
|
56
|
-
child.stderr.on('data', (chunk) => {
|
|
57
|
-
stderr += chunk
|
|
58
|
-
})
|
|
59
|
-
child.on('close', (status) => {
|
|
60
|
-
resolve({
|
|
61
|
-
status: status ?? 1,
|
|
62
|
-
stdout: stdout.trim(),
|
|
63
|
-
stderr: stderr.trim(),
|
|
64
|
-
command: [command, ...commandArgs].join(' '),
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function parseJson(stdout) {
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(stdout)
|
|
73
|
-
} catch {
|
|
74
|
-
return null
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function check(id, label, ok, evidence, risk = '') {
|
|
79
|
-
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function startServer() {
|
|
83
|
-
const server = http.createServer((request, response) => {
|
|
84
|
-
response.writeHead(200, { 'content-type': 'text/plain; charset=utf-8' })
|
|
85
|
-
response.end('gse fixture evidence\n')
|
|
86
|
-
})
|
|
87
|
-
return new Promise((resolve, reject) => {
|
|
88
|
-
server.once('error', reject)
|
|
89
|
-
server.listen(0, '127.0.0.1', () => {
|
|
90
|
-
const address = server.address()
|
|
91
|
-
resolve({ server, url: `http://127.0.0.1:${address.port}` })
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const probeScript = path.join(root, 'scripts', 'probe-public-external-gates.mjs')
|
|
97
|
-
const fixture = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-public-external-probe-'))
|
|
98
|
-
const hostEvidence = path.join(fixture, 'host-evidence.txt')
|
|
99
|
-
fs.writeFileSync(hostEvidence, 'fixture host transcript\n', 'utf8')
|
|
100
|
-
const { server, url } = await startServer()
|
|
101
|
-
|
|
102
|
-
let positive
|
|
103
|
-
let negativePlaceholder
|
|
104
|
-
let negativeMissingFile
|
|
105
|
-
let waiting
|
|
106
|
-
try {
|
|
107
|
-
positive = await runAsync(process.execPath, [
|
|
108
|
-
probeScript,
|
|
109
|
-
'--root', root,
|
|
110
|
-
'--allow-local-fixture',
|
|
111
|
-
'--timeout-ms', '3000',
|
|
112
|
-
'--public-repo-url', `${url}/repo`,
|
|
113
|
-
'--security-contact-url', `${url}/security`,
|
|
114
|
-
'--public-ci-run-url', `${url}/ci`,
|
|
115
|
-
'--registry-package-url', `${url}/package`,
|
|
116
|
-
'--marketplace-url', `${url}/marketplace`,
|
|
117
|
-
'--native-host-evidence', hostEvidence,
|
|
118
|
-
'--other-host-evidence', `${url}/host`,
|
|
119
|
-
'--json',
|
|
120
|
-
])
|
|
121
|
-
negativePlaceholder = run(process.execPath, [
|
|
122
|
-
probeScript,
|
|
123
|
-
'--root', root,
|
|
124
|
-
'--public-repo-url', 'https://github.com/example/gse',
|
|
125
|
-
'--registry-package-url', 'https://example.com/gse',
|
|
126
|
-
'--json',
|
|
127
|
-
])
|
|
128
|
-
negativeMissingFile = run(process.execPath, [
|
|
129
|
-
probeScript,
|
|
130
|
-
'--root', root,
|
|
131
|
-
'--native-host-evidence', path.join(fixture, 'missing.txt'),
|
|
132
|
-
'--json',
|
|
133
|
-
])
|
|
134
|
-
waiting = run(process.execPath, [probeScript, '--root', root, '--json'])
|
|
135
|
-
} finally {
|
|
136
|
-
await new Promise((resolve) => server.close(resolve))
|
|
137
|
-
fs.rmSync(fixture, { recursive: true, force: true })
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const positiveData = parseJson(positive.stdout)
|
|
141
|
-
const negativePlaceholderData = parseJson(negativePlaceholder.stdout)
|
|
142
|
-
const negativeMissingFileData = parseJson(negativeMissingFile.stdout)
|
|
143
|
-
const waitingData = parseJson(waiting.stdout)
|
|
144
|
-
const skill = read('SKILL.md')
|
|
145
|
-
const validate = read('scripts/validate-gse.mjs')
|
|
146
|
-
const completion = read('scripts/audit-completion-readiness.mjs')
|
|
147
|
-
const ownerKitGenerator = read('scripts/generate-owner-external-gate-kit.mjs')
|
|
148
|
-
const verificationCommands = read('.gse/acceptance/owner-external-gate-kit/verification-commands.md')
|
|
149
|
-
|
|
150
|
-
const checks = [
|
|
151
|
-
check('PEG01', 'public external gate probe exists', exists('scripts/probe-public-external-gates.mjs'), 'scripts/probe-public-external-gates.mjs'),
|
|
152
|
-
check('PEG02', 'probe accepts reachable evidence locations in fixture mode', positive.status === 0 && positiveData?.status === 'ready' && positiveData?.summary?.checked === 7 && positiveData?.summary?.failed === 0, positive.command),
|
|
153
|
-
check('PEG03', 'probe rejects placeholder and example public evidence', negativePlaceholder.status !== 0 && negativePlaceholderData?.status === 'failed' && negativePlaceholderData?.probes?.some((item) => item.errors?.some((error) => error.includes('not a placeholder'))), negativePlaceholder.command),
|
|
154
|
-
check('PEG04', 'probe rejects missing host evidence files', negativeMissingFile.status !== 0 && negativeMissingFileData?.status === 'failed' && negativeMissingFileData?.probes?.some((item) => item.errors?.some((error) => error.includes('existing evidence file'))), negativeMissingFile.command),
|
|
155
|
-
check('PEG05', 'probe can run without evidence inputs as a waiting diagnostic', waiting.status === 0 && waitingData?.status === 'waiting-for-input' && waitingData?.summary?.checked === 0, waiting.command),
|
|
156
|
-
check('PEG06', 'probe keeps acceptance boundary explicit', positiveData?.limits?.some((item) => item.includes('does not publish GSE')) && positiveData?.limits?.some((item) => item.includes('record script')), 'probe report limits'),
|
|
157
|
-
check('PEG07', 'GSE routing and owner kit mention the portable probe command', skill.includes('probe-public-external-gates.mjs') && ownerKitGenerator.includes('run-gse-command.mjs') && ownerKitGenerator.includes('/gse probe') && verificationCommands.includes('run-gse-command.mjs') && verificationCommands.includes('/gse probe') && !verificationCommands.includes('node scripts/probe-public-external-gates.mjs'), 'SKILL.md, generate-owner-external-gate-kit.mjs, owner kit verification commands'),
|
|
158
|
-
check('PEG08', 'validator and completion readiness include the probe audit', validate.includes('audit-public-external-gate-probe.mjs') && completion.includes('audit-public-external-gate-probe.mjs'), 'scripts/validate-gse.mjs, scripts/audit-completion-readiness.mjs'),
|
|
159
|
-
]
|
|
160
|
-
|
|
161
|
-
const passed = checks.filter((item) => item.status === 'passed').length
|
|
162
|
-
const failed = checks.length - passed
|
|
163
|
-
const report = {
|
|
164
|
-
root,
|
|
165
|
-
generatedAt: new Date().toISOString(),
|
|
166
|
-
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
167
|
-
workflows: {
|
|
168
|
-
publicExternalGateProbe: failed === 0 ? 'verified' : 'failed',
|
|
169
|
-
},
|
|
170
|
-
limits: [
|
|
171
|
-
'This audit verifies the probe mechanics with fixture evidence.',
|
|
172
|
-
'It does not create real public owner/external evidence or mark final readiness accepted.',
|
|
173
|
-
],
|
|
174
|
-
checks,
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function renderMarkdown(data) {
|
|
178
|
-
const lines = []
|
|
179
|
-
lines.push('# GSE Public External Gate Probe Audit')
|
|
180
|
-
lines.push('')
|
|
181
|
-
lines.push('Generated: ' + data.generatedAt)
|
|
182
|
-
lines.push('Root: ' + data.root)
|
|
183
|
-
lines.push('')
|
|
184
|
-
lines.push('## Summary')
|
|
185
|
-
lines.push('')
|
|
186
|
-
lines.push('- Status: ' + data.summary.status)
|
|
187
|
-
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
188
|
-
lines.push('- Public external gate probe: ' + data.workflows.publicExternalGateProbe)
|
|
189
|
-
lines.push('')
|
|
190
|
-
lines.push('## Checks')
|
|
191
|
-
lines.push('')
|
|
192
|
-
for (const item of data.checks) {
|
|
193
|
-
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
194
|
-
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
195
|
-
}
|
|
196
|
-
lines.push('')
|
|
197
|
-
lines.push('## Limits')
|
|
198
|
-
lines.push('')
|
|
199
|
-
for (const item of data.limits) lines.push('- ' + item)
|
|
200
|
-
return lines.join('\n') + '\n'
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
204
|
-
else console.log(renderMarkdown(report))
|
|
205
|
-
|
|
206
|
-
if (failed > 0) process.exit(1)
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import http from 'node:http'
|
|
4
|
+
import os from 'node:os'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import { spawn, spawnSync } from 'node:child_process'
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2)
|
|
9
|
+
|
|
10
|
+
function readArg(name, fallback = null) {
|
|
11
|
+
const index = args.indexOf(name)
|
|
12
|
+
if (index === -1) return fallback
|
|
13
|
+
return args[index + 1] ?? fallback
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
17
|
+
const jsonOnly = args.includes('--json')
|
|
18
|
+
|
|
19
|
+
function read(relativePath) {
|
|
20
|
+
const fullPath = path.join(root, relativePath)
|
|
21
|
+
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8') : ''
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function exists(relativePath) {
|
|
25
|
+
return fs.existsSync(path.join(root, relativePath))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function run(command, commandArgs) {
|
|
29
|
+
const result = spawnSync(command, commandArgs, {
|
|
30
|
+
cwd: root,
|
|
31
|
+
encoding: 'utf8',
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
})
|
|
34
|
+
return {
|
|
35
|
+
status: result.status ?? 1,
|
|
36
|
+
stdout: (result.stdout ?? '').trim(),
|
|
37
|
+
stderr: (result.stderr ?? '').trim(),
|
|
38
|
+
command: [command, ...commandArgs].join(' '),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function runAsync(command, commandArgs) {
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
const child = spawn(command, commandArgs, {
|
|
45
|
+
cwd: root,
|
|
46
|
+
windowsHide: true,
|
|
47
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
48
|
+
})
|
|
49
|
+
let stdout = ''
|
|
50
|
+
let stderr = ''
|
|
51
|
+
child.stdout.setEncoding('utf8')
|
|
52
|
+
child.stderr.setEncoding('utf8')
|
|
53
|
+
child.stdout.on('data', (chunk) => {
|
|
54
|
+
stdout += chunk
|
|
55
|
+
})
|
|
56
|
+
child.stderr.on('data', (chunk) => {
|
|
57
|
+
stderr += chunk
|
|
58
|
+
})
|
|
59
|
+
child.on('close', (status) => {
|
|
60
|
+
resolve({
|
|
61
|
+
status: status ?? 1,
|
|
62
|
+
stdout: stdout.trim(),
|
|
63
|
+
stderr: stderr.trim(),
|
|
64
|
+
command: [command, ...commandArgs].join(' '),
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseJson(stdout) {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(stdout)
|
|
73
|
+
} catch {
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
79
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function startServer() {
|
|
83
|
+
const server = http.createServer((request, response) => {
|
|
84
|
+
response.writeHead(200, { 'content-type': 'text/plain; charset=utf-8' })
|
|
85
|
+
response.end('gse fixture evidence\n')
|
|
86
|
+
})
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
server.once('error', reject)
|
|
89
|
+
server.listen(0, '127.0.0.1', () => {
|
|
90
|
+
const address = server.address()
|
|
91
|
+
resolve({ server, url: `http://127.0.0.1:${address.port}` })
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const probeScript = path.join(root, 'scripts', 'probe-public-external-gates.mjs')
|
|
97
|
+
const fixture = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-public-external-probe-'))
|
|
98
|
+
const hostEvidence = path.join(fixture, 'host-evidence.txt')
|
|
99
|
+
fs.writeFileSync(hostEvidence, 'fixture host transcript\n', 'utf8')
|
|
100
|
+
const { server, url } = await startServer()
|
|
101
|
+
|
|
102
|
+
let positive
|
|
103
|
+
let negativePlaceholder
|
|
104
|
+
let negativeMissingFile
|
|
105
|
+
let waiting
|
|
106
|
+
try {
|
|
107
|
+
positive = await runAsync(process.execPath, [
|
|
108
|
+
probeScript,
|
|
109
|
+
'--root', root,
|
|
110
|
+
'--allow-local-fixture',
|
|
111
|
+
'--timeout-ms', '3000',
|
|
112
|
+
'--public-repo-url', `${url}/repo`,
|
|
113
|
+
'--security-contact-url', `${url}/security`,
|
|
114
|
+
'--public-ci-run-url', `${url}/ci`,
|
|
115
|
+
'--registry-package-url', `${url}/package`,
|
|
116
|
+
'--marketplace-url', `${url}/marketplace`,
|
|
117
|
+
'--native-host-evidence', hostEvidence,
|
|
118
|
+
'--other-host-evidence', `${url}/host`,
|
|
119
|
+
'--json',
|
|
120
|
+
])
|
|
121
|
+
negativePlaceholder = run(process.execPath, [
|
|
122
|
+
probeScript,
|
|
123
|
+
'--root', root,
|
|
124
|
+
'--public-repo-url', 'https://github.com/example/gse',
|
|
125
|
+
'--registry-package-url', 'https://example.com/gse',
|
|
126
|
+
'--json',
|
|
127
|
+
])
|
|
128
|
+
negativeMissingFile = run(process.execPath, [
|
|
129
|
+
probeScript,
|
|
130
|
+
'--root', root,
|
|
131
|
+
'--native-host-evidence', path.join(fixture, 'missing.txt'),
|
|
132
|
+
'--json',
|
|
133
|
+
])
|
|
134
|
+
waiting = run(process.execPath, [probeScript, '--root', root, '--json'])
|
|
135
|
+
} finally {
|
|
136
|
+
await new Promise((resolve) => server.close(resolve))
|
|
137
|
+
fs.rmSync(fixture, { recursive: true, force: true })
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const positiveData = parseJson(positive.stdout)
|
|
141
|
+
const negativePlaceholderData = parseJson(negativePlaceholder.stdout)
|
|
142
|
+
const negativeMissingFileData = parseJson(negativeMissingFile.stdout)
|
|
143
|
+
const waitingData = parseJson(waiting.stdout)
|
|
144
|
+
const skill = read('SKILL.md')
|
|
145
|
+
const validate = read('scripts/validate-gse.mjs')
|
|
146
|
+
const completion = read('scripts/audit-completion-readiness.mjs')
|
|
147
|
+
const ownerKitGenerator = read('scripts/generate-owner-external-gate-kit.mjs')
|
|
148
|
+
const verificationCommands = read('.gse/acceptance/owner-external-gate-kit/verification-commands.md')
|
|
149
|
+
|
|
150
|
+
const checks = [
|
|
151
|
+
check('PEG01', 'public external gate probe exists', exists('scripts/probe-public-external-gates.mjs'), 'scripts/probe-public-external-gates.mjs'),
|
|
152
|
+
check('PEG02', 'probe accepts reachable evidence locations in fixture mode', positive.status === 0 && positiveData?.status === 'ready' && positiveData?.summary?.checked === 7 && positiveData?.summary?.failed === 0, positive.command),
|
|
153
|
+
check('PEG03', 'probe rejects placeholder and example public evidence', negativePlaceholder.status !== 0 && negativePlaceholderData?.status === 'failed' && negativePlaceholderData?.probes?.some((item) => item.errors?.some((error) => error.includes('not a placeholder'))), negativePlaceholder.command),
|
|
154
|
+
check('PEG04', 'probe rejects missing host evidence files', negativeMissingFile.status !== 0 && negativeMissingFileData?.status === 'failed' && negativeMissingFileData?.probes?.some((item) => item.errors?.some((error) => error.includes('existing evidence file'))), negativeMissingFile.command),
|
|
155
|
+
check('PEG05', 'probe can run without evidence inputs as a waiting diagnostic', waiting.status === 0 && waitingData?.status === 'waiting-for-input' && waitingData?.summary?.checked === 0, waiting.command),
|
|
156
|
+
check('PEG06', 'probe keeps acceptance boundary explicit', positiveData?.limits?.some((item) => item.includes('does not publish GSE')) && positiveData?.limits?.some((item) => item.includes('record script')), 'probe report limits'),
|
|
157
|
+
check('PEG07', 'GSE routing and owner kit mention the portable probe command', skill.includes('probe-public-external-gates.mjs') && ownerKitGenerator.includes('run-gse-command.mjs') && ownerKitGenerator.includes('/gse probe') && verificationCommands.includes('run-gse-command.mjs') && verificationCommands.includes('/gse probe') && !verificationCommands.includes('node scripts/probe-public-external-gates.mjs'), 'SKILL.md, generate-owner-external-gate-kit.mjs, owner kit verification commands'),
|
|
158
|
+
check('PEG08', 'validator and completion readiness include the probe audit', validate.includes('audit-public-external-gate-probe.mjs') && completion.includes('audit-public-external-gate-probe.mjs'), 'scripts/validate-gse.mjs, scripts/audit-completion-readiness.mjs'),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
162
|
+
const failed = checks.length - passed
|
|
163
|
+
const report = {
|
|
164
|
+
root,
|
|
165
|
+
generatedAt: new Date().toISOString(),
|
|
166
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
167
|
+
workflows: {
|
|
168
|
+
publicExternalGateProbe: failed === 0 ? 'verified' : 'failed',
|
|
169
|
+
},
|
|
170
|
+
limits: [
|
|
171
|
+
'This audit verifies the probe mechanics with fixture evidence.',
|
|
172
|
+
'It does not create real public owner/external evidence or mark final readiness accepted.',
|
|
173
|
+
],
|
|
174
|
+
checks,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function renderMarkdown(data) {
|
|
178
|
+
const lines = []
|
|
179
|
+
lines.push('# GSE Public External Gate Probe Audit')
|
|
180
|
+
lines.push('')
|
|
181
|
+
lines.push('Generated: ' + data.generatedAt)
|
|
182
|
+
lines.push('Root: ' + data.root)
|
|
183
|
+
lines.push('')
|
|
184
|
+
lines.push('## Summary')
|
|
185
|
+
lines.push('')
|
|
186
|
+
lines.push('- Status: ' + data.summary.status)
|
|
187
|
+
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
188
|
+
lines.push('- Public external gate probe: ' + data.workflows.publicExternalGateProbe)
|
|
189
|
+
lines.push('')
|
|
190
|
+
lines.push('## Checks')
|
|
191
|
+
lines.push('')
|
|
192
|
+
for (const item of data.checks) {
|
|
193
|
+
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
194
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
195
|
+
}
|
|
196
|
+
lines.push('')
|
|
197
|
+
lines.push('## Limits')
|
|
198
|
+
lines.push('')
|
|
199
|
+
for (const item of data.limits) lines.push('- ' + item)
|
|
200
|
+
return lines.join('\n') + '\n'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
204
|
+
else console.log(renderMarkdown(report))
|
|
205
|
+
|
|
206
|
+
if (failed > 0) process.exit(1)
|