@t275005746/gse 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/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
- package/.github/ISSUE_TEMPLATE/change_request.yml +50 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- package/.github/workflows/validate-gse.yml +33 -0
- package/.gse/README.md +18 -0
- package/.gse/gse-development-protocol.md +50 -0
- package/.gse/project-profile.md +29 -0
- package/.gse/quality-gates.md +25 -0
- package/.gse/releases/public-channel-publication-pending.md +49 -0
- package/.gse/releases/public-ci-run-pending.md +53 -0
- package/.gse/releases/public-release-owner-required.md +65 -0
- package/.gse/releases/public-repository-settings-owner-required.md +59 -0
- package/.gse/releases/public-security-contact-owner-required.md +45 -0
- package/.gse/state.json +27 -0
- package/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +64 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/README.zh-CN.md +236 -0
- package/SECURITY.md +41 -0
- package/SKILL.md +148 -0
- package/SUPPORT.md +38 -0
- package/agents/openai.yaml +4 -0
- package/assets/marketplace/README.md +7 -0
- package/assets/marketplace/gse-listing.json +75 -0
- package/assets/templates/acceptance-execution-packet.md +73 -0
- package/assets/templates/adr.md +14 -0
- package/assets/templates/change-brief.md +16 -0
- package/assets/templates/design.md +18 -0
- package/assets/templates/dispatch-packet.md +104 -0
- package/assets/templates/evidence.md +14 -0
- package/assets/templates/execution-quality-pack.md +65 -0
- package/assets/templates/goal-map.md +21 -0
- package/assets/templates/host-adapter.md +48 -0
- package/assets/templates/host-ui-invocation-record.md +42 -0
- package/assets/templates/incident-review.md +60 -0
- package/assets/templates/public-channel-publication-record.md +49 -0
- package/assets/templates/public-ci-run-record.md +53 -0
- package/assets/templates/public-release-record.md +65 -0
- package/assets/templates/public-repository-settings-record.md +59 -0
- package/assets/templates/public-security-contact-record.md +45 -0
- package/assets/templates/release-trust-record.md +32 -0
- package/assets/templates/review.md +18 -0
- package/assets/templates/spec.md +16 -0
- package/assets/templates/target-adoption-evidence.md +29 -0
- package/assets/templates/tasks.md +17 -0
- package/assets/templates/update-release-acceptance-record.md +58 -0
- package/examples/README.md +22 -0
- package/examples/agent-runtime-host/.claude/gse-adapter.md +6 -0
- package/examples/agent-runtime-host/.codex/gse-adapter.md +7 -0
- package/examples/agent-runtime-host/.gse/goal-map.md +7 -0
- package/examples/agent-runtime-host/.gse/project-profile.md +27 -0
- package/examples/agent-runtime-host/.gse/tooling.md +5 -0
- package/examples/agent-runtime-host/.mcp.json +9 -0
- package/examples/agent-runtime-host/AGENTS.md +5 -0
- package/examples/agent-runtime-host/README.md +10 -0
- package/examples/agent-runtime-host/docs/model-routing.md +5 -0
- package/examples/cli-tool/.gse/project-profile.md +21 -0
- package/examples/cli-tool/AGENTS.md +5 -0
- package/examples/cli-tool/README.md +12 -0
- package/examples/cli-tool/package.json +21 -0
- package/examples/small-app/.env.example +2 -0
- package/examples/small-app/.github/workflows/ci.yml +8 -0
- package/examples/small-app/AGENTS.md +5 -0
- package/examples/small-app/README.md +12 -0
- package/examples/small-app/package.json +26 -0
- package/examples/small-app/playwright.config.ts +4 -0
- package/package.json +53 -0
- package/references/adoption-recipes.md +171 -0
- package/references/agent-roles.md +49 -0
- package/references/architecture-health.md +101 -0
- package/references/benchmark-audit.md +73 -0
- package/references/commands.md +295 -0
- package/references/community-channels.md +46 -0
- package/references/compatibility.md +70 -0
- package/references/design-basis.md +38 -0
- package/references/domain-model.md +129 -0
- package/references/domain-quality-gates.md +75 -0
- package/references/drift-audit.md +81 -0
- package/references/evidence-taxonomy.md +123 -0
- package/references/file-ownership.md +107 -0
- package/references/final-readiness.md +84 -0
- package/references/forward-test.md +133 -0
- package/references/goal-map.md +36 -0
- package/references/host-adapters.md +119 -0
- package/references/learning-system.md +35 -0
- package/references/marketplace-discovery.md +46 -0
- package/references/model-routing.md +103 -0
- package/references/open-source-defaults.md +39 -0
- package/references/operating-model.md +52 -0
- package/references/packaging.md +277 -0
- package/references/project-agent-workspace.md +89 -0
- package/references/project-bootstrap.md +122 -0
- package/references/project-profile.md +57 -0
- package/references/public-release.md +174 -0
- package/references/quality-gates.md +100 -0
- package/references/recovery.md +176 -0
- package/references/release-trust.md +43 -0
- package/references/release.md +126 -0
- package/references/review.md +141 -0
- package/references/router.md +90 -0
- package/references/spec-workflow.md +66 -0
- package/references/task-levels.md +81 -0
- package/references/tool-adapters.md +73 -0
- package/scripts/audit-acceptance-execution-packet.mjs +133 -0
- package/scripts/audit-adoption-recipes.mjs +99 -0
- package/scripts/audit-adoption.mjs +154 -0
- package/scripts/audit-change-lifecycle.mjs +77 -0
- package/scripts/audit-change-system.mjs +134 -0
- package/scripts/audit-ci-readiness.mjs +107 -0
- package/scripts/audit-close-gate.mjs +323 -0
- package/scripts/audit-command-adapters.mjs +91 -0
- package/scripts/audit-command-execution.mjs +210 -0
- package/scripts/audit-commands.mjs +117 -0
- package/scripts/audit-compatibility.mjs +149 -0
- package/scripts/audit-completion-readiness.mjs +292 -0
- package/scripts/audit-distribution.mjs +251 -0
- package/scripts/audit-domain-quality-gates.mjs +108 -0
- package/scripts/audit-evidence-placeholders.mjs +126 -0
- package/scripts/audit-final-acceptance-packet.mjs +148 -0
- package/scripts/audit-final-form-progress-report.mjs +161 -0
- package/scripts/audit-final-form-stale-copy.mjs +221 -0
- package/scripts/audit-final-readiness-promotion.mjs +255 -0
- package/scripts/audit-final-readiness.mjs +226 -0
- package/scripts/audit-fixtures.mjs +154 -0
- package/scripts/audit-fresh-session-readiness.mjs +177 -0
- package/scripts/audit-gse.mjs +275 -0
- package/scripts/audit-host-adapters.mjs +119 -0
- package/scripts/audit-host-runtime-evidence-handoff.mjs +159 -0
- package/scripts/audit-host-runtime-invocation-drill.mjs +240 -0
- package/scripts/audit-host-runtime-invocations.mjs +254 -0
- package/scripts/audit-host-ui-invocation.mjs +132 -0
- package/scripts/audit-learning-system.mjs +103 -0
- package/scripts/audit-local-final-form-completion.mjs +131 -0
- package/scripts/audit-marketplace-discovery.mjs +122 -0
- package/scripts/audit-npm-package-metadata.mjs +155 -0
- package/scripts/audit-npm-publish-dry-run.mjs +169 -0
- package/scripts/audit-npm-tarball-install.mjs +191 -0
- package/scripts/audit-open-source-defaults.mjs +92 -0
- package/scripts/audit-open-source-readiness.mjs +97 -0
- package/scripts/audit-owner-external-gate-kit.mjs +218 -0
- package/scripts/audit-project.mjs +323 -0
- package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -0
- package/scripts/audit-public-acceptance-handoff.mjs +142 -0
- package/scripts/audit-public-acceptance-readiness.mjs +224 -0
- package/scripts/audit-public-channel-publication.mjs +248 -0
- package/scripts/audit-public-ci-run.mjs +184 -0
- package/scripts/audit-public-collaboration-templates.mjs +98 -0
- package/scripts/audit-public-external-gate-probe.mjs +206 -0
- package/scripts/audit-public-release-checklist.mjs +133 -0
- package/scripts/audit-public-release-decision.mjs +201 -0
- package/scripts/audit-public-release-metadata.mjs +176 -0
- package/scripts/audit-public-repository-settings.mjs +237 -0
- package/scripts/audit-public-security-contact.mjs +171 -0
- package/scripts/audit-readme-docs.mjs +185 -0
- package/scripts/audit-recovery-readiness.mjs +98 -0
- package/scripts/audit-release-bundle.mjs +251 -0
- package/scripts/audit-release-owner-action-plan-drill.mjs +277 -0
- package/scripts/audit-release-owner-action-plan.mjs +164 -0
- package/scripts/audit-release-readiness.mjs +106 -0
- package/scripts/audit-release-status-manifest.mjs +165 -0
- package/scripts/audit-release-trust.mjs +62 -0
- package/scripts/audit-remote-distribution.mjs +266 -0
- package/scripts/audit-roadmap-consistency.mjs +235 -0
- package/scripts/audit-signing.mjs +147 -0
- package/scripts/audit-state-freshness.mjs +113 -0
- package/scripts/audit-target-adoption-evidence.mjs +117 -0
- package/scripts/audit-target-project.mjs +507 -0
- package/scripts/audit-update-release-acceptance.mjs +136 -0
- package/scripts/audit-v1-target-validation.mjs +269 -0
- package/scripts/audit-validation-profiles.mjs +125 -0
- package/scripts/close-change.mjs +116 -0
- package/scripts/discover-project-profile.mjs +307 -0
- package/scripts/forward-test-gse.mjs +146 -0
- package/scripts/generate-command-adapter.mjs +231 -0
- package/scripts/generate-final-acceptance-packet.mjs +181 -0
- package/scripts/generate-final-form-progress-report.mjs +205 -0
- package/scripts/generate-host-adapter.mjs +73 -0
- package/scripts/generate-host-runtime-evidence-handoff.mjs +206 -0
- package/scripts/generate-owner-external-gate-kit.mjs +295 -0
- package/scripts/generate-public-acceptance-handoff.mjs +168 -0
- package/scripts/generate-public-release-checklist.mjs +207 -0
- package/scripts/generate-release-bundle.mjs +505 -0
- package/scripts/generate-release-owner-action-plan.mjs +172 -0
- package/scripts/generate-release-status-manifest.mjs +200 -0
- package/scripts/generate-session-prompt.mjs +188 -0
- package/scripts/gse.mjs +67 -0
- package/scripts/init-change.mjs +265 -0
- package/scripts/init-project.mjs +785 -0
- package/scripts/install-gse.mjs +234 -0
- package/scripts/lib/evidence-placeholders.mjs +28 -0
- package/scripts/package-gse.mjs +174 -0
- package/scripts/probe-public-external-gates.mjs +167 -0
- package/scripts/record-host-invocation.mjs +151 -0
- package/scripts/record-learning.mjs +137 -0
- package/scripts/record-public-channel-publication.mjs +178 -0
- package/scripts/record-public-ci-run.mjs +180 -0
- package/scripts/record-public-release.mjs +175 -0
- package/scripts/record-public-repository-settings.mjs +209 -0
- package/scripts/record-public-security-contact.mjs +157 -0
- package/scripts/run-gse-command.mjs +538 -0
- package/scripts/run-validation-profile.mjs +146 -0
- package/scripts/sign-gse-package.mjs +83 -0
- package/scripts/update-project-state.mjs +223 -0
- package/scripts/validate-gse.mjs +1168 -0
- package/scripts/verify-gse-package.mjs +85 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { mkdtempSync, rmSync } from 'node:fs'
|
|
5
|
+
import { tmpdir } from 'node:os'
|
|
6
|
+
import { 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 exists(relativePath) {
|
|
20
|
+
return fs.existsSync(path.join(root, relativePath))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function read(relativePath) {
|
|
24
|
+
const fullPath = path.join(root, relativePath)
|
|
25
|
+
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8').replace(/^\uFEFF/, '') : ''
|
|
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 parseJson(text) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(text)
|
|
45
|
+
} catch {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
51
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const generator = read('scripts/generate-release-status-manifest.mjs')
|
|
55
|
+
const validate = read('scripts/validate-gse.mjs')
|
|
56
|
+
const skill = read('SKILL.md')
|
|
57
|
+
const releaseGenerator = read('scripts/generate-release-bundle.mjs')
|
|
58
|
+
const releaseAudit = read('scripts/audit-release-bundle.mjs')
|
|
59
|
+
const tmp = mkdtempSync(path.join(tmpdir(), 'gse-release-status-manifest-'))
|
|
60
|
+
const out = path.join(tmp, 'release-status-manifest.json')
|
|
61
|
+
const generated = exists('scripts/generate-release-status-manifest.mjs')
|
|
62
|
+
? run(process.execPath, [path.join(root, 'scripts', 'generate-release-status-manifest.mjs'), '--root', root, '--out', out, '--force', '--json'])
|
|
63
|
+
: null
|
|
64
|
+
const generatedData = generated ? parseJson(generated.stdout) : null
|
|
65
|
+
const manifest = fs.existsSync(out) ? parseJson(fs.readFileSync(out, 'utf8')) : null
|
|
66
|
+
rmSync(tmp, { recursive: true, force: true })
|
|
67
|
+
|
|
68
|
+
const requiredArtifacts = [
|
|
69
|
+
'finalAcceptancePacket',
|
|
70
|
+
'publicAcceptanceHandoff',
|
|
71
|
+
'hostRuntimeEvidenceHandoff',
|
|
72
|
+
'releaseStatusManifest',
|
|
73
|
+
]
|
|
74
|
+
const requiredDistribution = [
|
|
75
|
+
'localPackage',
|
|
76
|
+
'localInstall',
|
|
77
|
+
'localInstalledCli',
|
|
78
|
+
'remoteInstall',
|
|
79
|
+
'remoteInstalledCli',
|
|
80
|
+
'integrityGate',
|
|
81
|
+
'packageSigning',
|
|
82
|
+
'signatureVerification',
|
|
83
|
+
'releaseBundle',
|
|
84
|
+
]
|
|
85
|
+
const requiredCommands = [
|
|
86
|
+
'validate-gse.mjs',
|
|
87
|
+
'audit-final-readiness.mjs',
|
|
88
|
+
'audit-public-acceptance-readiness.mjs',
|
|
89
|
+
'audit-public-acceptance-command-dry-run-drill.mjs',
|
|
90
|
+
'audit-host-runtime-invocations.mjs',
|
|
91
|
+
'audit-host-runtime-invocation-drill.mjs',
|
|
92
|
+
'audit-release-bundle.mjs',
|
|
93
|
+
]
|
|
94
|
+
const verificationCommandsAreShellSafe = (manifest?.verificationCommands?.length ?? 0) > 0 &&
|
|
95
|
+
manifest.verificationCommands.every((command) => !/[<>]/.test(command) && command.includes('__GSE__'))
|
|
96
|
+
|
|
97
|
+
const checks = [
|
|
98
|
+
check('RSM01', 'release status manifest generator exists', exists('scripts/generate-release-status-manifest.mjs'), 'scripts/generate-release-status-manifest.mjs'),
|
|
99
|
+
check('RSM02', 'generator composes authoritative non-circular audits', ['audit-final-readiness.mjs', 'audit-public-acceptance-readiness.mjs', 'audit-host-runtime-invocations.mjs', 'audit-host-runtime-invocation-drill.mjs'].every((term) => generator.includes(term)) && !generator.includes("audit('audit-release-bundle.mjs')") && !generator.includes("audit('audit-distribution.mjs')"), 'generator source audits'),
|
|
100
|
+
check('RSM03', 'generator writes parseable manifest', generated?.status === 0 && generatedData?.status === 'written' && manifest?.schemaVersion === 1, generated?.stderr || out),
|
|
101
|
+
check('RSM04', 'manifest preserves public acceptance boundary', manifest?.claimBoundary?.publicAccepted === 'not-accepted' && manifest?.claimBoundary?.localValidationDoesNotMeanPublicAcceptance === true, 'publicAccepted not-accepted'),
|
|
102
|
+
check('RSM05', 'manifest covers verified rows and current owner/external rows', (manifest?.readiness?.verified?.length ?? 0) > 0 && ((manifest?.readiness?.ownerRequired?.length ?? 0) + (manifest?.readiness?.externalRequired?.length ?? 0)) > 0, 'readiness row groups'),
|
|
103
|
+
check('RSM06', 'manifest covers install and distribution status', requiredDistribution.every((key) => manifest?.distribution?.[key]), requiredDistribution.join(', ')),
|
|
104
|
+
check('RSM07', 'manifest covers public acceptance next commands', (manifest?.publicAcceptance?.pendingGates?.length ?? 0) > 0 && (manifest?.publicAcceptance?.nextCommands?.length ?? 0) === (manifest?.publicAcceptance?.pendingGates?.length ?? -1), 'pending gates and next commands'),
|
|
105
|
+
check('RSM07b', 'manifest covers public acceptance dry-run preflight commands', (manifest?.publicAcceptance?.pendingGates?.length ?? 0) > 0 && (manifest?.publicAcceptance?.nextPreflightCommands?.length ?? 0) === (manifest?.publicAcceptance?.pendingGates?.length ?? -1) && manifest.publicAcceptance.nextPreflightCommands.every((command) => command.includes('--dry-run --json')), 'pending gates and preflight commands'),
|
|
106
|
+
check('RSM08', 'manifest covers host runtime evidence counts', Number.isInteger(manifest?.hostRuntime?.nativeSlashCommandRecords) && Number.isInteger(manifest?.hostRuntime?.portableTextCommandRecords) && manifest.hostRuntime.nativeSlashCommandRecords >= 0 && manifest.hostRuntime.portableTextCommandRecords >= 0, `native ${manifest?.hostRuntime?.nativeSlashCommandRecords ?? 'unknown'}, portable ${manifest?.hostRuntime?.portableTextCommandRecords ?? 'unknown'}`),
|
|
107
|
+
check('RSM08b', 'manifest covers host runtime fixture drill status', manifest?.hostRuntime?.fixtureDrill === 'verified' && manifest?.hostRuntime?.fixtureNativeSlashCommandRecords === 1 && manifest?.hostRuntime?.fixturePortableTextCommandRecords === 4 && manifest?.hostRuntime?.fixtureEvidenceIsPersistent === false, `drill ${manifest?.hostRuntime?.fixtureDrill ?? 'unknown'}, fixture native ${manifest?.hostRuntime?.fixtureNativeSlashCommandRecords ?? 'unknown'}, fixture portable ${manifest?.hostRuntime?.fixturePortableTextCommandRecords ?? 'unknown'}`),
|
|
108
|
+
check('RSM09', 'manifest points to handoff artifacts', requiredArtifacts.every((key) => manifest?.artifacts?.[key]), requiredArtifacts.join(', ')),
|
|
109
|
+
check('RSM10', 'manifest includes verification commands', requiredCommands.every((term) => manifest?.verificationCommands?.some((command) => command.includes(term))), requiredCommands.join(', ')),
|
|
110
|
+
check('RSM11', 'skill routes users to release status manifest', skill.includes('generate-release-status-manifest.mjs'), 'SKILL.md'),
|
|
111
|
+
check('RSM12', 'validator includes release status manifest audit', validate.includes('audit-release-status-manifest.mjs'), 'scripts/validate-gse.mjs'),
|
|
112
|
+
check('RSM13', 'release bundle includes release status manifest', releaseGenerator.includes('release-status-manifest.json') && releaseAudit.includes('release-status-manifest.json'), 'release bundle generator and audit'),
|
|
113
|
+
check('RSM14', 'manifest verification commands use shell-safe placeholders', verificationCommandsAreShellSafe, 'verification commands use __GSE__ instead of <gse>'),
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
117
|
+
const failed = checks.length - passed
|
|
118
|
+
const report = {
|
|
119
|
+
root,
|
|
120
|
+
generatedAt: new Date().toISOString(),
|
|
121
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
122
|
+
workflows: {
|
|
123
|
+
releaseStatusManifest: failed === 0 ? 'verified' : 'failed',
|
|
124
|
+
publicAccepted: manifest?.claimBoundary?.publicAccepted ?? 'unknown',
|
|
125
|
+
pendingGates: manifest?.publicAcceptance?.pendingGates?.length ?? 'unknown',
|
|
126
|
+
},
|
|
127
|
+
limits: [
|
|
128
|
+
'This audit verifies manifest generation from local audits.',
|
|
129
|
+
'It does not create owner decisions, public CI, public repository settings, marketplace approval, registry publication, or native slash-command evidence.',
|
|
130
|
+
],
|
|
131
|
+
checks,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function renderMarkdown(data) {
|
|
135
|
+
const lines = []
|
|
136
|
+
lines.push('# GSE Release Status Manifest Audit')
|
|
137
|
+
lines.push('')
|
|
138
|
+
lines.push('Generated: ' + data.generatedAt)
|
|
139
|
+
lines.push('Root: ' + data.root)
|
|
140
|
+
lines.push('')
|
|
141
|
+
lines.push('## Summary')
|
|
142
|
+
lines.push('')
|
|
143
|
+
lines.push('- Status: ' + data.summary.status)
|
|
144
|
+
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
145
|
+
lines.push('- Release status manifest: ' + data.workflows.releaseStatusManifest)
|
|
146
|
+
lines.push('- Public accepted: ' + data.workflows.publicAccepted)
|
|
147
|
+
lines.push('- Pending gates: ' + data.workflows.pendingGates)
|
|
148
|
+
lines.push('')
|
|
149
|
+
lines.push('## Checks')
|
|
150
|
+
lines.push('')
|
|
151
|
+
for (const item of data.checks) {
|
|
152
|
+
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
153
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
154
|
+
}
|
|
155
|
+
lines.push('')
|
|
156
|
+
lines.push('## Limits')
|
|
157
|
+
lines.push('')
|
|
158
|
+
for (const item of data.limits) lines.push('- ' + item)
|
|
159
|
+
return lines.join('\n') + '\n'
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
163
|
+
else console.log(renderMarkdown(report))
|
|
164
|
+
|
|
165
|
+
if (failed > 0) process.exit(1)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2)
|
|
6
|
+
|
|
7
|
+
function readArg(name, fallback = null) {
|
|
8
|
+
const index = args.indexOf(name)
|
|
9
|
+
if (index === -1) return fallback
|
|
10
|
+
return args[index + 1] ?? fallback
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
14
|
+
const jsonOnly = args.includes('--json')
|
|
15
|
+
|
|
16
|
+
function read(relativePath) {
|
|
17
|
+
const fullPath = path.join(root, relativePath)
|
|
18
|
+
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8') : ''
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function exists(relativePath) {
|
|
22
|
+
return fs.existsSync(path.join(root, relativePath))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
26
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const trust = read('references/release-trust.md')
|
|
30
|
+
const template = read('assets/templates/release-trust-record.md')
|
|
31
|
+
const packaging = read('references/packaging.md')
|
|
32
|
+
const validate = read('scripts/validate-gse.mjs')
|
|
33
|
+
|
|
34
|
+
const checks = [
|
|
35
|
+
check('TRUST01', 'release trust reference exists', exists('references/release-trust.md'), 'references/release-trust.md'),
|
|
36
|
+
check('TRUST02', 'release trust template exists', exists('assets/templates/release-trust-record.md'), 'assets/templates/release-trust-record.md'),
|
|
37
|
+
check('TRUST03', 'trust reference separates signed verified trusted', ['signed', 'verified', 'trusted', 'Do not claim `trusted` from signing alone.'].every((term) => trust.includes(term)), 'references/release-trust.md'),
|
|
38
|
+
check('TRUST04', 'trust reference defines key custody and revocation', ['Key custody', 'Rotation policy', 'Revocation path', 'Do not commit private keys'].every((term) => trust.includes(term)), 'references/release-trust.md'),
|
|
39
|
+
check('TRUST05', 'template captures owner acceptance and public key fingerprint', ['Public key fingerprint', 'Accepted by', 'Private key location', 'Verification command'].every((term) => template.includes(term)), 'release-trust-record.md'),
|
|
40
|
+
check('TRUST06', 'packaging routes readers to signing and trust rules', packaging.includes('Signing And Verification') && packaging.includes('Release Trust'), 'references/packaging.md'),
|
|
41
|
+
check('TRUST07', 'validator includes release trust audit', validate.includes('audit-release-trust.mjs'), 'scripts/validate-gse.mjs'),
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
45
|
+
const failed = checks.length - passed
|
|
46
|
+
const report = {
|
|
47
|
+
root,
|
|
48
|
+
generatedAt: new Date().toISOString(),
|
|
49
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
50
|
+
workflows: { releaseTrustPolicy: failed === 0 ? 'verified' : 'failed' },
|
|
51
|
+
limits: [
|
|
52
|
+
'This audit verifies release trust policy and template coverage.',
|
|
53
|
+
'It does not prove a real maintainer identity, key custody event, marketplace approval, or production release acceptance.',
|
|
54
|
+
],
|
|
55
|
+
checks,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
59
|
+
else console.log(JSON.stringify(report, null, 2))
|
|
60
|
+
|
|
61
|
+
if (failed > 0) process.exit(1)
|
|
62
|
+
|
|
@@ -0,0 +1,266 @@
|
|
|
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
|
+
const profile = readArg('--profile', 'full')
|
|
19
|
+
if (!['smoke', 'full'].includes(profile)) {
|
|
20
|
+
console.error('Unsupported --profile. Expected smoke or full.')
|
|
21
|
+
process.exit(1)
|
|
22
|
+
}
|
|
23
|
+
const smokeProfile = profile === 'smoke'
|
|
24
|
+
|
|
25
|
+
function run(command, commandArgs, cwd = root) {
|
|
26
|
+
const result = spawnSync(command, commandArgs, {
|
|
27
|
+
cwd,
|
|
28
|
+
encoding: 'utf8',
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
})
|
|
31
|
+
return {
|
|
32
|
+
command: [command, ...commandArgs].join(' '),
|
|
33
|
+
status: result.status ?? 1,
|
|
34
|
+
stdout: (result.stdout ?? '').trim(),
|
|
35
|
+
stderr: (result.stderr ?? '').trim(),
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function runAsync(command, commandArgs, cwd = root) {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
const child = spawn(command, commandArgs, { cwd, windowsHide: true })
|
|
42
|
+
let stdout = ''
|
|
43
|
+
let stderr = ''
|
|
44
|
+
child.stdout.on('data', (chunk) => { stdout += chunk.toString('utf8') })
|
|
45
|
+
child.stderr.on('data', (chunk) => { stderr += chunk.toString('utf8') })
|
|
46
|
+
child.on('close', (status) => {
|
|
47
|
+
resolve({
|
|
48
|
+
command: [command, ...commandArgs].join(' '),
|
|
49
|
+
status: status ?? 1,
|
|
50
|
+
stdout: stdout.trim(),
|
|
51
|
+
stderr: stderr.trim(),
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function parseJson(text) {
|
|
58
|
+
try { return JSON.parse(text) } catch { return null }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
62
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function skipped(id, label, evidence, risk = '') {
|
|
66
|
+
return { id, label, status: 'skipped', evidence, risk }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function runInstalledPackageValidation(target) {
|
|
70
|
+
const validationCommands = [
|
|
71
|
+
['audit-gse.mjs', ['--root', target, '--json']],
|
|
72
|
+
['audit-project.mjs', ['--root', target, '--json']],
|
|
73
|
+
['audit-fixtures.mjs', ['--root', target, '--json']],
|
|
74
|
+
['audit-commands.mjs', ['--root', target, '--json']],
|
|
75
|
+
['audit-command-execution.mjs', ['--root', target, '--profile', 'lite', '--json']],
|
|
76
|
+
['audit-readme-docs.mjs', ['--root', target, '--json']],
|
|
77
|
+
['audit-open-source-readiness.mjs', ['--root', target, '--json']],
|
|
78
|
+
['audit-marketplace-discovery.mjs', ['--root', target, '--json']],
|
|
79
|
+
['generate-session-prompt.mjs', ['--root', target, '--json']],
|
|
80
|
+
]
|
|
81
|
+
const results = validationCommands.map(([script, commandArgs]) => {
|
|
82
|
+
const result = run(process.execPath, [path.join(target, 'scripts', script), ...commandArgs], target)
|
|
83
|
+
const parsed = parseJson(result.stdout)
|
|
84
|
+
const failed = parsed?.summary?.failed
|
|
85
|
+
const ok = result.status === 0 || failed === 0
|
|
86
|
+
return {
|
|
87
|
+
script,
|
|
88
|
+
command: result.command,
|
|
89
|
+
status: result.status,
|
|
90
|
+
ok,
|
|
91
|
+
summary: parsed?.summary ?? null,
|
|
92
|
+
stderr: result.stderr,
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
const passed = results.filter((item) => item.ok).length
|
|
96
|
+
const failed = results.length - passed
|
|
97
|
+
return {
|
|
98
|
+
command: 'remote installed package validation: ' + validationCommands.map(([script]) => script).join(', '),
|
|
99
|
+
status: failed === 0 ? 0 : 1,
|
|
100
|
+
stdout: JSON.stringify({
|
|
101
|
+
summary: {
|
|
102
|
+
status: failed === 0 ? 'passed' : 'failed',
|
|
103
|
+
passed,
|
|
104
|
+
failed,
|
|
105
|
+
total: results.length,
|
|
106
|
+
},
|
|
107
|
+
results,
|
|
108
|
+
limits: [
|
|
109
|
+
'Installed-package validation checks portable skill structure, bootstrap fixtures, command semantics, lite command execution, README docs, open-source readiness, marketplace metadata, and session prompt generation.',
|
|
110
|
+
'It intentionally excludes source-workspace-only roadmap, long evidence logs, release-bundle cache, and owner/external acceptance artifacts.',
|
|
111
|
+
],
|
|
112
|
+
}),
|
|
113
|
+
stderr: results.filter((item) => !item.ok).map((item) => item.script + ': ' + item.stderr).filter(Boolean).join('\n'),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function contentType(filePath) {
|
|
118
|
+
if (filePath.endsWith('.json')) return 'application/json'
|
|
119
|
+
if (filePath.endsWith('.md')) return 'text/markdown; charset=utf-8'
|
|
120
|
+
if (filePath.endsWith('.mjs')) return 'text/javascript; charset=utf-8'
|
|
121
|
+
return 'application/octet-stream'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function createStaticServer(baseDir) {
|
|
125
|
+
const server = http.createServer((request, response) => {
|
|
126
|
+
try {
|
|
127
|
+
const url = new URL(request.url ?? '/', 'http://127.0.0.1')
|
|
128
|
+
const relativePath = decodeURIComponent(url.pathname.replace(/^\/+/, '')) || 'gse-package-manifest.json'
|
|
129
|
+
const fullPath = path.resolve(baseDir, relativePath)
|
|
130
|
+
if (!fullPath.startsWith(path.resolve(baseDir))) {
|
|
131
|
+
response.writeHead(403)
|
|
132
|
+
response.end('Forbidden')
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
|
|
136
|
+
response.writeHead(404)
|
|
137
|
+
response.end('Not found')
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
response.writeHead(200, { 'content-type': contentType(fullPath) })
|
|
141
|
+
fs.createReadStream(fullPath).pipe(response)
|
|
142
|
+
} catch (error) {
|
|
143
|
+
response.writeHead(500)
|
|
144
|
+
response.end(error instanceof Error ? error.message : String(error))
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
return new Promise((resolve) => {
|
|
148
|
+
server.listen(0, '127.0.0.1', () => {
|
|
149
|
+
const address = server.address()
|
|
150
|
+
resolve({ server, baseUrl: `http://127.0.0.1:${address.port}/` })
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-remote-distribution-'))
|
|
156
|
+
const packageOut = path.join(tempRoot, 'package')
|
|
157
|
+
const installTarget = path.join(tempRoot, 'installed-gse')
|
|
158
|
+
const tamperedTarget = path.join(tempRoot, 'tampered-install')
|
|
159
|
+
|
|
160
|
+
const packageRun = run(process.execPath, [
|
|
161
|
+
path.join(root, 'scripts', 'package-gse.mjs'),
|
|
162
|
+
'--root',
|
|
163
|
+
root,
|
|
164
|
+
'--out',
|
|
165
|
+
packageOut,
|
|
166
|
+
'--label',
|
|
167
|
+
'gse-remote-audit',
|
|
168
|
+
'--json',
|
|
169
|
+
])
|
|
170
|
+
const packageData = parseJson(packageRun.stdout)
|
|
171
|
+
|
|
172
|
+
const manifestPath = path.join(packageOut, 'gse-package-manifest.json')
|
|
173
|
+
const manifest = fs.existsSync(manifestPath) ? JSON.parse(fs.readFileSync(manifestPath, 'utf8')) : null
|
|
174
|
+
|
|
175
|
+
let server
|
|
176
|
+
let baseUrl = ''
|
|
177
|
+
let remoteInstall = { status: 1, command: 'not-run', stdout: '', stderr: '' }
|
|
178
|
+
let installedValidate = { status: 1, command: 'not-run', stdout: '', stderr: '' }
|
|
179
|
+
let installedCli = { status: 1, command: 'not-run', stdout: '', stderr: '' }
|
|
180
|
+
let tamperedInstall = { status: 1, command: 'not-run', stdout: '', stderr: '' }
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const started = await createStaticServer(packageOut)
|
|
184
|
+
server = started.server
|
|
185
|
+
baseUrl = started.baseUrl
|
|
186
|
+
remoteInstall = await runAsync(process.execPath, [
|
|
187
|
+
path.join(root, 'scripts', 'install-gse.mjs'),
|
|
188
|
+
'--source-url',
|
|
189
|
+
baseUrl,
|
|
190
|
+
'--target',
|
|
191
|
+
installTarget,
|
|
192
|
+
'--json',
|
|
193
|
+
])
|
|
194
|
+
installedValidate = smokeProfile
|
|
195
|
+
? { status: 0, command: 'skipped by --profile smoke', stdout: '', stderr: '' }
|
|
196
|
+
: runInstalledPackageValidation(installTarget)
|
|
197
|
+
installedCli = await runAsync(process.execPath, [
|
|
198
|
+
path.join(installTarget, 'scripts', 'gse.mjs'),
|
|
199
|
+
'status',
|
|
200
|
+
'--target',
|
|
201
|
+
installTarget,
|
|
202
|
+
'--json',
|
|
203
|
+
], installTarget)
|
|
204
|
+
|
|
205
|
+
fs.appendFileSync(path.join(packageOut, 'README.md'), '\nTampered for integrity audit.\n', 'utf8')
|
|
206
|
+
tamperedInstall = await runAsync(process.execPath, [
|
|
207
|
+
path.join(root, 'scripts', 'install-gse.mjs'),
|
|
208
|
+
'--source-url',
|
|
209
|
+
baseUrl,
|
|
210
|
+
'--target',
|
|
211
|
+
tamperedTarget,
|
|
212
|
+
'--json',
|
|
213
|
+
])
|
|
214
|
+
} finally {
|
|
215
|
+
if (server) await new Promise((resolve) => server.close(resolve))
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const remoteInstallData = parseJson(remoteInstall.stdout)
|
|
219
|
+
const installedValidateData = parseJson(installedValidate.stdout)
|
|
220
|
+
const installedCliData = parseJson(installedCli.stdout)
|
|
221
|
+
const tamperedInstallData = parseJson(tamperedInstall.stdout)
|
|
222
|
+
|
|
223
|
+
const checks = [
|
|
224
|
+
check('RD01', 'package manifest includes sha256 file hashes', packageRun.status === 0 && manifest?.integrity?.algorithm === 'sha256' && manifest?.fileHashes?.['SKILL.md'], 'gse-package-manifest.json'),
|
|
225
|
+
check('RD02', 'HTTP package source served manifest and files', Boolean(baseUrl) && remoteInstall.status === 0, baseUrl),
|
|
226
|
+
check('RD03', 'install-gse supports --source-url', remoteInstall.status === 0 && remoteInstallData?.sourceMode === 'http-url', remoteInstall.command),
|
|
227
|
+
check('RD04', 'remote install validates file integrity', remoteInstall.status === 0 && remoteInstallData?.summary?.integrityFailed === 0 && remoteInstallData?.integrity?.algorithm === 'sha256', 'install summary integrity'),
|
|
228
|
+
smokeProfile
|
|
229
|
+
? skipped('RD05', 'remote installed copy validates', installedValidate.command, 'Run --profile full for remote installed-copy validation.')
|
|
230
|
+
: check('RD05', 'remote installed copy validates', installedValidate.status === 0 && installedValidateData?.summary?.failed === 0, installedValidate.command),
|
|
231
|
+
check('RD06', 'remote installed short CLI wrapper runs status command', installedCli.status === 0 && installedCliData?.command === '/gse status' && installedCliData?.project?.stateValid === true, installedCli.command),
|
|
232
|
+
check('RD07', 'tampered remote package fails integrity gate', tamperedInstall.status === 1 && tamperedInstallData?.summary?.integrityFailed > 0, 'tampered README.md install'),
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
236
|
+
const skippedCount = checks.filter((item) => item.status === 'skipped').length
|
|
237
|
+
const failed = checks.filter((item) => item.status === 'failed').length
|
|
238
|
+
const report = {
|
|
239
|
+
root,
|
|
240
|
+
generatedAt: new Date().toISOString(),
|
|
241
|
+
tempRoot,
|
|
242
|
+
baseUrl,
|
|
243
|
+
profile,
|
|
244
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, skipped: skippedCount, total: checks.length },
|
|
245
|
+
workflows: {
|
|
246
|
+
remoteInstall: remoteInstall.status === 0 ? 'verified' : 'failed',
|
|
247
|
+
integrityGate: tamperedInstall.status === 1 ? 'verified' : 'failed',
|
|
248
|
+
installedValidation: smokeProfile ? 'skipped' : installedValidate.status === 0 ? 'verified' : 'failed',
|
|
249
|
+
installedCli: installedCli.status === 0 ? 'verified' : 'failed',
|
|
250
|
+
},
|
|
251
|
+
commands: [packageRun.command, remoteInstall.command, installedValidate.command, installedCli.command, tamperedInstall.command],
|
|
252
|
+
limits: [
|
|
253
|
+
'This audit verifies HTTP URL install through a local ephemeral server and manifest integrity checks.',
|
|
254
|
+
'Use --profile smoke for routine remote install, CLI, and integrity checks; use --profile full before release or when installed-copy validation matters.',
|
|
255
|
+
'Installed-package validation intentionally excludes source-workspace-only roadmap, long evidence logs, release-bundle cache, and owner/external acceptance artifacts.',
|
|
256
|
+
'It does not publish to a public registry, verify marketplace discovery, or sign artifacts with a trusted key.',
|
|
257
|
+
],
|
|
258
|
+
checks,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
262
|
+
|
|
263
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
264
|
+
else console.log(JSON.stringify(report, null, 2))
|
|
265
|
+
|
|
266
|
+
if (failed > 0) process.exit(1)
|