diff --git a/CHANGELOG.md b/CHANGELOG.md index 079373e..aeb6379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ CodeTruss CLI follows semantic versioning. Release artifacts and their SHA-256 checksums are published at . -The current public release is [v0.2.53 on GitHub](https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.53), +The current public release is [v0.2.55 on GitHub](https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.55), distributed from . The npm `latest` tag is still [`@codetruss/cli@0.2.50`](https://www.npmjs.com/package/@codetruss/cli/v/0.2.50): @@ -16,6 +16,110 @@ were superseded before distribution. No unreleased changes. +## 0.2.55 — 2026-08-08 + +Nine green CI contexts gated every release before this one, and none of them could +see a rule. + +The public mirror carries `packages/cli/` and `packages/analyzer-engine/`'s +`package.json` and `src`. It carries no root `tests/`, and `analyzer-engine` has no +test directory to carry. The rule-level SAST suites live in the monorepo — +`tests/sast-regressions.test.ts` exercises the hosted `@/lib/security/**` +implementation, and `tests/analyzer-engine-parity.test.ts` is what binds that +implementation to the shipped engine — and neither reaches the mirror. What the nine +OS × Node contexts and the tag-triggered release job verified was **packaging**: a +reproducible archive, a verifier that rejects tampering, a changelog chain, a README +whose profile id matches the code. A SAST behaviour regression could pass all nine. + +That is not hypothetical. Both 0.2.53 fixes were confirmed by an acceptance check run +by hand, and the false positive one of them removed had already shipped. + +- **The release now runs the shipped binary over fixtures before it is a release.** + `packages/cli/scripts/test-acceptance.mjs` executes the built `dist/cli.cjs` — not + `src/`, not the hosted implementation — over the committed tree in + `scripts/fixtures/acceptance/`, and asserts the findings the release must and must + not produce. It joins `test-deterministic-package.mjs`, `test-release-verifier.mjs` + and `test-changelog-policy.mjs` in this package's `test` script, so it runs in all + nine compatibility contexts and in the release job, from inside the mirror, with no + hosted code present. + + Two fixtures, both single file shapes, both reproducing findings recorded in + `docs/benchmarks/cross-tool-2026-08/adjudication/verdicts.md`. A drizzle `` sql`…` `` + tagged template with interpolations, which must NOT be reported (it was CWE-89 + CRITICAL until 0.2.53). And `client.query(param, …)` on a database-shaped receiver, + which must be reported at HIGH on the `client.query` line (silent until 0.2.53; + Semgrep caught it and we did not). + + The check was verified in both directions rather than assumed: reverting the 0.2.53 + tagged-template exemption turns it red with the original `CRITICAL sql-injection at + src/db/rpc.ts`, and reverting the caller-supplied-argument report turns it red with + zero findings where one is required. + + The ten benchmark repositories are deliberately not cloned. Minutes of network across + nine contexts, and a release that would depend on third-party repositories staying up. + +- **It refuses to test a bundle that is not this release.** A test that read `src/` + would recreate the gap it exists to close, so the script checks `dist/cli.cjs + --version` against `package.json` and refuses to run if any file under + `packages/cli/src` or `packages/analyzer-engine/src` is newer than the bundle. Both + refusals were demonstrated: the published 0.2.53 `dist/cli.cjs` is rejected by + version, and a touched rule source is rejected as unbuilt. + + Fixtures are committed with a `.fixture` suffix and materialized at run time, so the + repository's own lint and typecheck programs never compile deliberately vulnerable + code, and the analyzer still sees `.ts` and `.js` where it matters. + +- **`CONTRIBUTING.md` now says what mirror CI verifies.** It described the artifact and + grammar-pack verifiers accurately and left the rest to inference, and the inference + everyone drew — nine green contexts mean the release behaves — was wrong until this + entry. + +No analyzer, rule, or receipt behaviour changes in this release. The archive differs +from 0.2.54 only in the changelog it carries. + +## 0.2.54 — 2026-08-08 + +The 0.2.53 archive contradicted itself. `README.md` said receipts identify the +15-pass `local-registry-v4` profile; `CHANGELOG.md`, packed beside it in the same +tarball, said the profile is `local-registry-v5`. The pass count was right and +the profile bump was right — only the identifier in the README was stale, +because the 0.2.53 commit changed `LOCAL_ANALYSIS_PROFILE.id` and never touched +the prose that restates it. + +**The published 0.2.53 bytes are unchanged.** They are tagged, attested, and +served; the correction ships here. + +- **The README states the current profile id.** `packages/cli/README.md` now + reads `local-registry-v5`. Three further copies outside the archive said `v4` + for the same reason and are corrected too: the monorepo `README.md` (twice) and + `docs/codetruss-cli-guide.md`, including the sample receipt's profile line. + +- **A build step now fails when the README's profile id or analyzer count does + not match the code.** This is the second escape of exactly this defect — the + README carried `local-registry-v3` after v4 shipped, corrected in 0.2.44 — so + the identifier is no longer maintained by hand alone. + `scripts/docs-profile-policy.mjs` reads `LOCAL_ANALYSIS_PROFILE.id` from + `packages/cli/src/types.ts` and the analyzer count from `ANALYZERS` in + `packages/analyzer-engine/src/registry.ts`, and `build-release.mjs` asserts the + README agrees with both — beside `assertChangelogPolicy`, guarding the + CHANGELOG's peer in the same eight-file archive, and before any archive bytes + exist, because this script refuses to overwrite an already-written versioned + tarball. It runs wherever a release is built, including all nine CI + compatibility contexts and the tag-triggered release job. + + The extractor reads TypeScript textually, because the release build runs under + plain Node and cannot import it. That seam is closed rather than trusted: it + throws instead of guessing when either source stops parsing, and + `tests/docs-profile-claims.test.ts` imports the real constants and asserts the + extracted values equal them. That test also guards the two monorepo documents, + which never reach the archive. + + What separated the strings 0.2.53 updated from the strings it missed was not + care, it was coverage: the marketing demo string was updated because a test + asserts it contains `LOCAL_ANALYSIS_PROFILE.id`, and the receipt page copy was + updated because a zod literal would not compile otherwise. Every restatement + nothing checked stayed stale. + ## 0.2.53 — 2026-08-08 We published what we missed. This release publishes what we got wrong. diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 3d6b227..a618a1a 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -5,6 +5,110 @@ checksums are published at ${params.team_id}, p_url => ${params.url})`, + ); +} diff --git a/packages/cli/scripts/fixtures/acceptance/src/monitor/postgres.js.fixture b/packages/cli/scripts/fixtures/acceptance/src/monitor/postgres.js.fixture new file mode 100644 index 0000000..3865e76 --- /dev/null +++ b/packages/cli/scripts/fixtures/acceptance/src/monitor/postgres.js.fixture @@ -0,0 +1,24 @@ +// Shape of louislam/uptime-kuma `server/monitor-types/postgres.js:35-63`, the +// true positive recorded in docs/benchmarks/cross-tool-2026-08/adjudication/ +// verdicts.md ("...and the same rule missed a real dynamic query"). Semgrep +// flagged it as node-postgres-sqli; CodeTruss reported nothing in that file +// until CLI 0.2.53. The whole query text arrives as a parameter, the receiver +// is database-shaped, and no call site in this file binds a constant or a +// tagged template to it. MUST be reported as sql-injection. +class PostgresMonitorType extends MonitorType { + async check(monitor, heartbeat) { + let query = monitor.databaseQuery; + await this.postgresQuery(monitor.databaseConnectionString, query); + } + + async postgresQuery(connectionString, query) { + return new Promise((resolve, reject) => { + const client = new Client(postgresConParse(connectionString)); + client.connect((err) => { + client.query(query, (err2, res) => { + resolve(res); + }); + }); + }); + } +} diff --git a/packages/cli/scripts/test-acceptance.mjs b/packages/cli/scripts/test-acceptance.mjs new file mode 100644 index 0000000..65680ad --- /dev/null +++ b/packages/cli/scripts/test-acceptance.mjs @@ -0,0 +1,254 @@ +// Behaviour acceptance test for the SHIPPED CLI. +// +// Everything else in this package's `test` script checks packaging: the archive +// is reproducible, the verifier rejects tampering, the changelog forms a chain. +// None of it runs a rule. The public mirror carries no root `tests/` and no +// `packages/analyzer-engine/test/`, so the nine CI compatibility contexts and +// the tag-triggered release job could go green over a SAST behaviour regression +// — which is how the two findings below shipped and were caught by hand. +// +// This script closes that. It executes the built `dist/cli.cjs` over a committed +// fixture tree and asserts the findings the release must and must not produce. +// It lives under `packages/cli/`, so it reaches the mirror with the rest of the +// package and needs no hosted-app implementation to run. +// +// The expected verdicts are taken from the committed adjudication at +// `docs/benchmarks/cross-tool-2026-08/adjudication/verdicts.md`, sections +// "CodeTruss reported a parameterized query as CRITICAL SQL injection" +// (firecrawl `apps/api/src/db/rpc.ts:98`) and "…and the same rule missed a real +// dynamic query" (uptime-kuma `server/monitor-types/postgres.js:35-63`). The +// benchmark repositories are deliberately NOT cloned here: minutes of network +// across nine contexts, and a release that depends on third-party repositories +// staying alive. +import assert from 'node:assert/strict' +import { spawnSync } from 'node:child_process' +import { mkdir, mkdtemp, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { dirname, join, relative, resolve, sep } from 'node:path' +import { fileURLToPath } from 'node:url' + +const scriptDir = dirname(fileURLToPath(import.meta.url)) +const packageDir = resolve(scriptDir, '..') +const workspaceRoot = resolve(packageDir, '../..') +const bundle = join(packageDir, 'dist', 'cli.cjs') +const fixtureRoot = join(scriptDir, 'fixtures', 'acceptance') +const FIXTURE_SUFFIX = '.fixture' + +/** + * What the shipped engine must say about each fixture. + * + * `line` is not written down: it is located in the fixture text by `anchor`, so + * editing a fixture cannot silently retarget the assertion at a different + * statement, and reformatting one does not produce a false failure. + */ +const EXPECTED = [ + { + path: 'src/db/rpc.ts', + ruleId: 'sql-injection', + reported: false, + why: 'drizzle `sql` tagged template — interpolations are bound parameters, not concatenation (fixed in 0.2.53)', + }, + { + path: 'src/monitor/postgres.js', + ruleId: 'sql-injection', + reported: true, + anchor: 'client.query(query', + severity: 'HIGH', + cwe: 'CWE-89', + messageIncludes: 'query', + why: 'the whole query text is a function parameter on a database-shaped receiver (added in 0.2.53)', + }, +] + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { + cwd: options.cwd ?? packageDir, + encoding: 'utf8', + env: { ...process.env, ...options.env }, + windowsHide: true, + }) + if (result.error) throw result.error + const allowed = options.exitCodes ?? [0] + if (!allowed.includes(result.status)) { + throw new Error(`${command} ${args.join(' ')} exited with ${result.status}\n${result.stdout ?? ''}${result.stderr ?? ''}`) + } + // stdout only: a warning on stderr must not become part of a parsed report. + return result.stdout ?? '' +} + +/** Absolute paths of every file under `dir`, recursively. */ +async function filesUnder(dir) { + const entries = await readdir(dir, { withFileTypes: true, recursive: true }) + return entries.filter((e) => e.isFile()).map((e) => join(e.parentPath ?? e.path, e.name)) +} + +/** + * Refuse to run against a bundle that is not this working tree's code. + * + * The point of this file is to test the artifact a user installs, so a stale + * `dist/cli.cjs` — one built before the source edit under review, or left over + * from another release — would report the old engine's verdicts and pass. That + * is the same green-badge-means-nothing failure this script exists to close, so + * it is checked rather than assumed. `pretest` rebuilds, so this only fires when + * the script is run on its own after an edit. + */ +async function assertBundleIsCurrent(version) { + const built = await stat(bundle).catch(() => { + throw new Error(`${bundle} does not exist; run \`pnpm cli:build\` (a fresh worktree has no dist/)`) + }) + const reported = run(process.execPath, [bundle, '--version']).trim() + assert.equal( + reported, + `codetruss ${version}`, + `dist/cli.cjs reports "${reported}" but package.json declares ${version}; the bundle is not this release`, + ) + const sourceTrees = [join(packageDir, 'src'), join(workspaceRoot, 'packages', 'analyzer-engine', 'src')] + for (const tree of sourceTrees) { + for (const file of await filesUnder(tree)) { + const source = await stat(file) + if (source.mtimeMs > built.mtimeMs) { + throw new Error( + `${relative(workspaceRoot, file)} is newer than dist/cli.cjs; this would test a stale bundle. ` + + 'Run `pnpm cli:build` (or `pnpm --filter @codetruss/cli test`, whose pretest builds).', + ) + } + } + } + return sourceTrees.map((tree) => relative(workspaceRoot, tree)) +} + +/** Copy the fixture tree into `target`, stripping the `.fixture` suffix. */ +async function materializeFixtures(target) { + const sources = await filesUnder(fixtureRoot) + assert.ok(sources.length > 0, `no fixtures found under ${fixtureRoot}`) + const written = new Map() + for (const source of sources) { + assert.ok( + source.endsWith(FIXTURE_SUFFIX), + `${relative(fixtureRoot, source)} must end in ${FIXTURE_SUFFIX} so the repository's own lint and ` + + 'typecheck programs do not compile deliberately vulnerable code', + ) + const logical = relative(fixtureRoot, source).slice(0, -FIXTURE_SUFFIX.length).split(sep).join('/') + const text = await readFile(source, 'utf8') + const destination = join(target, ...logical.split('/')) + await mkdir(dirname(destination), { recursive: true }) + await writeFile(destination, text) + written.set(logical, text) + } + return written +} + +/** Run `review` then `report --json` in `repo`, and return the local-sast findings. */ +function scan(repo, home, fixtureCount) { + const env = { + // Keep the run off the developer's (and the runner's) real config: the CLI + // stores its signing key and verify-trust decisions under the user config + // root, and this test must not create or consume either. + CODETRUSS_SIGNING_KEY: join(home, 'signing-private.pem'), + XDG_CONFIG_HOME: home, + } + const git = (...args) => run('git', ['-C', repo, ...args]) + git('init', '--quiet', '-b', 'main', '.') + // The CLI reports the delta against a baseline commit. An empty baseline — + // the policy file alone — makes the whole fixture tree the change, which is + // the same construction `docs/benchmarks/cross-tool-2026-08/lib/run-codetruss.sh` + // uses to scan a whole repository. + run(process.execPath, [bundle, 'init', '--force', '--allow', '**'], { cwd: repo, env }) + git('add', '-f', '.codetruss.yml') + git( + '-c', 'user.email=acceptance@codetruss.local', + '-c', 'user.name=CodeTruss Acceptance', + '-c', 'commit.gpgsign=false', + 'commit', '--quiet', '-m', 'acceptance fixture baseline', + ) + // PASS=0 and REVIEW_REQUIRED=1 are both valid outcomes; the verdict is not + // what is under test, the findings are. FAILED=2 and usage=3 are not. + run(process.execPath, [bundle, 'review', '--task', 'CLI acceptance fixture scan', '--no-verify'], { + cwd: repo, + env, + exitCodes: [0, 1], + }) + const report = JSON.parse(run(process.execPath, [bundle, 'report', 'latest', '--json'], { cwd: repo, env })) + const pass = report.analyzers?.passes?.find((p) => p.id === 'local-sast') + assert.ok(pass, 'the receipt has no local-sast pass; the security analyzer did not run at all') + assert.equal(pass.result.complete, true, 'the local-sast pass did not complete over two small fixtures') + assert.equal(pass.result.truncated, false, 'the local-sast pass truncated over two small fixtures') + assert.equal( + pass.result.metrics?.filesScanned, + fixtureCount, + `local-sast scanned ${pass.result.metrics?.filesScanned} of ${fixtureCount} fixtures; every fixture must reach the engine`, + ) + return pass.result.findings +} + +const version = JSON.parse(await readFile(join(packageDir, 'package.json'), 'utf8')).version +const covered = await assertBundleIsCurrent(version) +const scratch = await mkdtemp(join(tmpdir(), 'codetruss-cli-acceptance-')) +const repo = join(scratch, 'repo') +const home = join(scratch, 'config') +await mkdir(repo, { recursive: true }) +await mkdir(home, { recursive: true }) + +try { + const fixtures = await materializeFixtures(repo) + const findings = scan(repo, home, fixtures.size) + const failures = [] + + for (const expectation of EXPECTED) { + const source = fixtures.get(expectation.path) + assert.ok(source, `EXPECTED names ${expectation.path}, which no fixture produces`) + const matched = findings.filter( + (f) => f.filePath === expectation.path && f.metadata?.ruleId === expectation.ruleId, + ) + const describe = (f) => `${f.severity} ${f.metadata?.ruleId} at ${f.filePath}:${f.line} — ${f.title}` + + if (!expectation.reported) { + if (matched.length > 0) { + failures.push( + `${expectation.path}: expected NO ${expectation.ruleId} finding (${expectation.why}), got ` + + `${matched.length}:\n ${matched.map(describe).join('\n ')}`, + ) + } + continue + } + + if (matched.length !== 1) { + failures.push( + `${expectation.path}: expected exactly 1 ${expectation.ruleId} finding (${expectation.why}), got ` + + `${matched.length}${matched.length ? `:\n ${matched.map(describe).join('\n ')}` : ''}`, + ) + continue + } + const [finding] = matched + const anchorLine = source.split('\n').findIndex((line) => line.includes(expectation.anchor)) + 1 + assert.ok(anchorLine > 0, `fixture ${expectation.path} no longer contains \`${expectation.anchor}\``) + if (finding.line !== anchorLine) { + failures.push(`${expectation.path}: ${expectation.ruleId} reported at line ${finding.line}, expected ${anchorLine} (\`${expectation.anchor}\`)`) + } + if (finding.severity !== expectation.severity) { + failures.push(`${expectation.path}: ${expectation.ruleId} severity ${finding.severity}, expected ${expectation.severity}`) + } + if (finding.metadata?.cwe !== expectation.cwe) { + failures.push(`${expectation.path}: ${expectation.ruleId} cwe ${finding.metadata?.cwe}, expected ${expectation.cwe}`) + } + if (!finding.description?.includes(expectation.messageIncludes)) { + failures.push(`${expectation.path}: ${expectation.ruleId} message does not name \`${expectation.messageIncludes}\`: ${finding.description}`) + } + } + + if (failures.length > 0) { + throw new Error( + `The shipped CLI ${version} does not behave as the benchmark adjudication requires:\n - ` + + `${failures.join('\n - ')}\n\n` + + 'These fixtures reproduce findings recorded in docs/benchmarks/cross-tool-2026-08/adjudication/verdicts.md. ' + + 'Do not relax the assertion to make this pass.', + ) + } + + process.stdout.write( + `acceptance: dist/cli.cjs ${version} (newer than ${covered.join(' and ')}) reproduced ` + + `${EXPECTED.length} adjudicated verdicts over ${fixtures.size} fixtures\n`, + ) +} finally { + await rm(scratch, { recursive: true, force: true }) +} diff --git a/public/downloads/codetruss-cli-0.2.55.sbom.cdx.json b/public/downloads/codetruss-cli-0.2.55.sbom.cdx.json new file mode 100644 index 0000000..805188c --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.55.sbom.cdx.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "serialNumber": "urn:uuid:63871415-7d51-553a-a7f2-6f45a8317154", + "specVersion": "1.6", + "version": 1, + "metadata": { + "component": { + "type": "application", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.55", + "name": "@codetruss/cli", + "version": "0.2.55", + "description": "Local-first scope, quality, and verification receipts for coding agents", + "licenses": [ + { + "license": { + "name": "CodeTruss CLI Proprietary License" + } + } + ], + "purl": "pkg:npm/%40codetruss/cli@0.2.55" + }, + "properties": [ + { + "name": "codetruss:distribution", + "value": "single-file JavaScript bundle" + }, + { + "name": "codetruss:runtimeDependencies", + "value": "0" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "name": "@codetruss/analyzer-engine", + "version": "0.1.0", + "licenses": [ + { + "license": { + "name": "CodeTruss CLI Proprietary License" + } + } + ], + "purl": "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/balanced-match@4.0.4", + "name": "balanced-match", + "version": "4.0.4", + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ], + "purl": "pkg:npm/balanced-match@4.0.4", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/brace-expansion@5.0.9", + "name": "brace-expansion", + "version": "5.0.9", + "licenses": [ + { + "license": { + "id": "MIT" + } + } + ], + "purl": "pkg:npm/brace-expansion@5.0.9", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/minimatch@10.2.6", + "name": "minimatch", + "version": "10.2.6", + "licenses": [ + { + "license": { + "id": "BlueOak-1.0.0" + } + } + ], + "purl": "pkg:npm/minimatch@10.2.6", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + }, + { + "type": "library", + "bom-ref": "pkg:npm/yaml@2.9.0", + "name": "yaml", + "version": "2.9.0", + "licenses": [ + { + "license": { + "id": "ISC" + } + } + ], + "purl": "pkg:npm/yaml@2.9.0", + "properties": [ + { + "name": "codetruss:bundled", + "value": "true" + } + ] + } + ], + "dependencies": [ + { + "ref": "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "dependsOn": [] + }, + { + "ref": "pkg:npm/%40codetruss/cli@0.2.55", + "dependsOn": [ + "pkg:npm/%40codetruss/analyzer-engine@0.1.0", + "pkg:npm/minimatch@10.2.6", + "pkg:npm/yaml@2.9.0" + ] + }, + { + "ref": "pkg:npm/balanced-match@4.0.4", + "dependsOn": [] + }, + { + "ref": "pkg:npm/brace-expansion@5.0.9", + "dependsOn": [ + "pkg:npm/balanced-match@4.0.4" + ] + }, + { + "ref": "pkg:npm/minimatch@10.2.6", + "dependsOn": [ + "pkg:npm/brace-expansion@5.0.9" + ] + }, + { + "ref": "pkg:npm/yaml@2.9.0", + "dependsOn": [] + } + ] +} diff --git a/public/downloads/codetruss-cli-0.2.55.tgz b/public/downloads/codetruss-cli-0.2.55.tgz new file mode 100644 index 0000000..fac4487 Binary files /dev/null and b/public/downloads/codetruss-cli-0.2.55.tgz differ diff --git a/public/downloads/codetruss-cli-0.2.55.tgz.sha256 b/public/downloads/codetruss-cli-0.2.55.tgz.sha256 new file mode 100644 index 0000000..98752a1 --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.55.tgz.sha256 @@ -0,0 +1 @@ +12010c43b6635c5e5384a753bd5467bfa7031f64403ccdf0acfa5f9baa150194 codetruss-cli-0.2.55.tgz diff --git a/public/downloads/codetruss-cli-latest.json b/public/downloads/codetruss-cli-latest.json index f8f72f3..83f7677 100644 --- a/public/downloads/codetruss-cli-latest.json +++ b/public/downloads/codetruss-cli-latest.json @@ -1,13 +1,13 @@ { "name": "@codetruss/cli", - "version": "0.2.53", - "url": "/downloads/codetruss-cli-0.2.53.tgz", + "version": "0.2.55", + "url": "/downloads/codetruss-cli-0.2.55.tgz", "latestUrl": "/downloads/codetruss-cli-latest.tgz", - "sha256": "5344ab8e32c5ccd0093d17088c520aa685b988423a0890de29cbaac1c96c2aca", - "sbomUrl": "/downloads/codetruss-cli-0.2.53.sbom.cdx.json", - "sbomSha256": "de3b934c62aacb467b7ce333faeebf3a79e7f6d6c2476e3da4113e9c61fa5d12", + "sha256": "12010c43b6635c5e5384a753bd5467bfa7031f64403ccdf0acfa5f9baa150194", + "sbomUrl": "/downloads/codetruss-cli-0.2.55.sbom.cdx.json", + "sbomSha256": "4225420f1f3e39630e9c0bcda70ed480f259daaebdd0e9cd1a05264e726131c2", "node": ">=20.9.0", "repository": "https://github.com/CodeTruss/codetruss-cli", - "releaseUrl": "https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.53", - "attestationCommand": "gh attestation verify codetruss-cli-0.2.53.tgz --repo CodeTruss/codetruss-cli" + "releaseUrl": "https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.55", + "attestationCommand": "gh attestation verify codetruss-cli-0.2.55.tgz --repo CodeTruss/codetruss-cli" } diff --git a/public/downloads/codetruss-cli-latest.sbom.cdx.json b/public/downloads/codetruss-cli-latest.sbom.cdx.json index 17b62a2..805188c 100644 --- a/public/downloads/codetruss-cli-latest.sbom.cdx.json +++ b/public/downloads/codetruss-cli-latest.sbom.cdx.json @@ -1,15 +1,15 @@ { "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", "bomFormat": "CycloneDX", - "serialNumber": "urn:uuid:6d901377-79c0-50cd-84dd-46fc5c7c62c0", + "serialNumber": "urn:uuid:63871415-7d51-553a-a7f2-6f45a8317154", "specVersion": "1.6", "version": 1, "metadata": { "component": { "type": "application", - "bom-ref": "pkg:npm/%40codetruss/cli@0.2.53", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.55", "name": "@codetruss/cli", - "version": "0.2.53", + "version": "0.2.55", "description": "Local-first scope, quality, and verification receipts for coding agents", "licenses": [ { @@ -18,7 +18,7 @@ } } ], - "purl": "pkg:npm/%40codetruss/cli@0.2.53" + "purl": "pkg:npm/%40codetruss/cli@0.2.55" }, "properties": [ { @@ -139,7 +139,7 @@ "dependsOn": [] }, { - "ref": "pkg:npm/%40codetruss/cli@0.2.53", + "ref": "pkg:npm/%40codetruss/cli@0.2.55", "dependsOn": [ "pkg:npm/%40codetruss/analyzer-engine@0.1.0", "pkg:npm/minimatch@10.2.6", diff --git a/public/downloads/codetruss-cli-latest.tgz b/public/downloads/codetruss-cli-latest.tgz index cc6ebfd..fac4487 100644 Binary files a/public/downloads/codetruss-cli-latest.tgz and b/public/downloads/codetruss-cli-latest.tgz differ diff --git a/public/downloads/codetruss-cli-latest.tgz.sha256 b/public/downloads/codetruss-cli-latest.tgz.sha256 index 28c2d72..bb1f4c4 100644 --- a/public/downloads/codetruss-cli-latest.tgz.sha256 +++ b/public/downloads/codetruss-cli-latest.tgz.sha256 @@ -1 +1 @@ -5344ab8e32c5ccd0093d17088c520aa685b988423a0890de29cbaac1c96c2aca codetruss-cli-latest.tgz +12010c43b6635c5e5384a753bd5467bfa7031f64403ccdf0acfa5f9baa150194 codetruss-cli-latest.tgz diff --git a/release-reference.json b/release-reference.json index 7694598..50abc9f 100644 --- a/release-reference.json +++ b/release-reference.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, - "version": "0.2.53", - "websiteArchive": "https://codetruss.com/downloads/codetruss-cli-0.2.53.tgz", - "archiveSha256": "5344ab8e32c5ccd0093d17088c520aa685b988423a0890de29cbaac1c96c2aca", - "sbomSha256": "de3b934c62aacb467b7ce333faeebf3a79e7f6d6c2476e3da4113e9c61fa5d12", - "bundleSha256": "1052b1a0fc8f0a7b36ff32cf2e916f113af9e949437bebb0fcb19e751fe65b0d" + "version": "0.2.55", + "websiteArchive": "https://codetruss.com/downloads/codetruss-cli-0.2.55.tgz", + "archiveSha256": "12010c43b6635c5e5384a753bd5467bfa7031f64403ccdf0acfa5f9baa150194", + "sbomSha256": "4225420f1f3e39630e9c0bcda70ed480f259daaebdd0e9cd1a05264e726131c2", + "bundleSha256": "a53585bac24ac520779c0740e92c24dd0d3f2d6bb0430b9921a087cf11b71637" }