diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe03fc..86fd61b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,18 +3,97 @@ CodeTruss CLI follows semantic versioning. Release artifacts and their SHA-256 checksums are published at . -The current public release is [v0.2.57 on GitHub](https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.57), +The current public release is [v0.2.61 on GitHub](https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.61), distributed from . -The npm `latest` tag is still -[`@codetruss/cli@0.2.50`](https://www.npmjs.com/package/@codetruss/cli/v/0.2.50): -npm publication is a separate, manually dispatched step, so npm can trail the -website and the GitHub release. +npm publication is a separate, manually dispatched step, so the npm `latest` +tag can trail the website and the GitHub release; the dispatch for this +version accompanies the release. Entries explicitly marked `(unpublished)` are retained release candidates that were superseded before distribution. ## Unreleased -No unreleased changes. +## 0.2.61 — 2026-08-08 + +- **Two path-traversal findings on the hook-result writer are dismissed with + their reason, in the code.** The flagged lines build a temp path from + `request.path` and open it — after that value has passed three containment + gates: the absolute-and-normalized check, lexical containment inside the + turn directory, and the deterministic attempt-location assertion. The rule + flagged the code that implements the containment, and the dismissal now + travels with the code as a reasoned `codetruss-ignore` marker, priced at + zero by scoring and shown on every receipt with the explanation above. No + behavior changes in this release; the two markers are its only code change. + +## 0.2.60 — 2026-08-08 + +- **A dismissed finding no longer charges the score.** A finding carrying a + reasoned `codetruss-ignore` marker already stays on every receipt as + evidence and already stops gating the verdict — that is what dismissing it + is for. But `computeScores` still priced it like a live finding, which + scored this product's own repository 32 on Security over its own annotated + acceptance fixtures: planted credentials that exist to prove the analyzers + fire, each disclosed with its reason on every receipt, all charged as leaks. + + Scoring now applies the same principle the verdict has applied since the + suppression mechanism was hardened: dismissed findings are evidence, not + charges. A marker without a reason never applied in the first place and + still charges; the identical finding without a marker still charges. Both + are pinned by tests, and removing the filter fails them. + +## 0.2.59 — 2026-08-08 + +- **The first line CodeTruss prints no longer opens with a zero.** In a + repository with no `.codetruss.yml` — which is every repository the first time + someone runs it — a passing review reported `0 changed file(s) are within + approved scope; 1 more matched scope inferred from this turn`. Every word of + that is true. It also reads as "nothing was checked", which is the opposite of + what happened: the file was in scope, it was analysed, and a finding was + reported against it. + + It now leads with the count actually in scope: `1 changed file(s) matched + scope inferred from this turn and disclosed on the receipt; none matched an + approved allow root`. The distinction the old sentence existed to protect is + kept — scope reached by inference is still never called approved scope, and + the receipt still lists every inferred root with the evidence it came from. + The wording says "none matched an approved allow root" rather than "this + repository approves nothing", because a repository whose allow roots simply + did not match these files is not a repository without any. + + Found by installing the published tarball into a clean prefix and running + `codetruss review --staged` on `axios/axios` as a new user would, rather than + by reading the code. + +## 0.2.58 — 2026-08-08 + +- **Prose describing a credential pattern is no longer reported as a leak.** + This scanner was run over its own source and reported three of its own doc + comments: the note explaining why `password = "password"` stays reported, and + two citing the fabricated key used to explain how typed-not-generated values + are recognized. 0.2.57 failed its own commit gate on the first of them, which + is the clearest possible statement of the problem — the comment documenting a + rule tripped the rule it documents. Any project that writes about credential + handling hits this: a security policy quoting the shape it forbids, a README + showing what not to commit, a lint rule explaining its own pattern. + + A code span on a comment line is the shape, but it is deliberately NOT the + exemption, because backticks would otherwise be a place to hide a live key. + The value also has to be independently provable as not-a-credential, by one of + two anchors that already existed here and were already measured: the value + spells out its own key, so it carries no entropy the key did not already + carry; or its body was typed rather than generated, eight consecutive stepping + characters, a threshold 20,000 random bodies fail to reach. A genuinely random + value quoted in a comment satisfies neither and is still reported, as is a + commented-out assignment holding a real key — that has no code span — and the + same fabricated body in executable code, which is not prose. + + The skip is announced rather than silent, at INFO, exactly as a + credential-shaped placeholder already is. A secret scanner that quietly drops + lines is indistinguishable from one that never read them. + + Measured before shipping on the adjudicated cross-tool corpus plus six more + repositories — about 26,000 files, 235 findings — where nothing changed at + all. The only findings this moves are the three in our own source. ## 0.2.57 — 2026-08-08 diff --git a/packages/analyzer-engine/src/scoring.ts b/packages/analyzer-engine/src/scoring.ts index e68bc73..107c014 100644 --- a/packages/analyzer-engine/src/scoring.ts +++ b/packages/analyzer-engine/src/scoring.ts @@ -140,7 +140,15 @@ function deduct(findings: AnalyzerFinding[], categories: string[], totalLoc: num const NEUTRAL_SCORE = 50 /** Deterministic 0-100 scores derived from findings + repo shape. */ -export function computeScores(index: RepoIndex, findings: AnalyzerFinding[]): Scores { +export function computeScores(index: RepoIndex, allFindings: AnalyzerFinding[]): Scores { + // A finding a developer dismissed with a reasoned `codetruss-ignore` marker + // stays on every report as evidence — but it stops scoring, for the same + // reason it already stops gating the CLI verdict: that is what dismissing it + // is for. Charging for it anyway scored this product's own repository 32 on + // Security over its own annotated acceptance fixtures — planted, reasoned, + // and disclosed on every receipt, yet priced like leaks. Markers without a + // reason never applied in the first place (suppression.ts) and still charge. + const findings = allFindings.filter((f) => !f.suppression?.applied) const loc = index.totalLoc const debt = deduct(findings, ['TECH_DEBT', 'DUPLICATION', 'DEAD_CODE'], loc) let security = deduct(findings, ['SECURITY_HYGIENE', 'DEPENDENCY'], loc) diff --git a/packages/analyzer-engine/src/secrets.ts b/packages/analyzer-engine/src/secrets.ts index 50bae10..434b777 100644 --- a/packages/analyzer-engine/src/secrets.ts +++ b/packages/analyzer-engine/src/secrets.ts @@ -292,6 +292,54 @@ function restatesItsKey(line: string, matchIndex: number, value: string): boolea return valueWords.length >= 2 && isWordRun(valueWords, identifierWords(assignedKey(line, matchIndex))) } +/** + * Prose quoting a credential pattern in order to describe it, rather than an + * assignment that sets one. + * + * This scanner was run over its own source and reported three of its own + * doc comments: the note on restatesItsKey, which quotes `password = + * "password"` to explain why that shape stays reported, and two that cite + * `AKIA1234567890ABCDEF` while explaining how fabricated keys are recognized. + * CLI 0.2.57 failed its own gate on the first of them. + * + * A code span on a comment line is the shape, but it is NOT the exemption — + * backticks alone would be a place to hide a live key. The exemption is that + * the value is independently provable as not-a-credential, by one of two + * anchors that already exist here and are already measured: + * + * - {@link hasSyntheticSequence}: the body was typed, not generated. Eight + * consecutive stepping characters; 20,000 random bodies produce zero hits. + * - The one-word restatement from {@link restatesItsKey}: the value spells + * out its own key, so it carries no entropy the key did not already carry. + * + * Every other half stays reported, and each closes a different hole. A + * commented-out assignment holding a real key (`// const apiKey = + * "sk-live-…"`) has no code span. A template literal in executable code is not + * on a comment line. A genuinely random value quoted in a comment satisfies + * neither anchor. + * + * Comment detection is deliberately the unambiguous prefix only. Tracking open + * block comments across lines would let a stray `/*` inside a string silence + * every line after it, and a wrong answer here hides a credential. + */ +function documentsAnExample(line: string, match: RegExpMatchArray, subject: string | null): boolean { + const matchIndex = match.index ?? 0 + const trimmed = line.trimStart() + if (!trimmed.startsWith('*') && !trimmed.startsWith('//') && !trimmed.startsWith('#')) return false + + // Odd backtick count before the match means it opened inside a span; a + // closing backtick after it means the span encloses the match. + const openedBefore = (line.slice(0, matchIndex).match(/`/g) ?? []).length % 2 === 1 + if (!openedBefore || !line.slice(matchIndex + match[0].length).includes('`')) return false + + if (subject !== null && hasSyntheticSequence(subject)) return true + + const quoted = /['"]([^'"]+)['"]/.exec(match[0])?.[1] + if (quoted === undefined) return false + const valueWords = identifierWords(quoted) + return valueWords.length === 1 && isWordRun(valueWords, identifierWords(assignedKey(line, matchIndex))) +} + /** Dev/CI dummy hosts — credentials pointing here are not real secrets. */ const DUMMY_HOSTS = new Set(['localhost', '127.0.0.1', '0.0.0.0', '::1', 'host.docker.internal']) @@ -489,6 +537,24 @@ export const secretsAnalyzer: Analyzer = { })) break } + // Announced rather than silent, for the same reason the placeholder + // skip above is: a secret scanner that quietly drops lines is + // indistinguishable from one that never read them. + if (documentsAnExample(line, match, subject)) { + report(() => ({ + category: 'SECURITY_HYGIENE', + severity: 'INFO', + title: `Documented ${name} example ignored in ${file.path.split('/').pop()}`, + description: `Line ${i + 1} of ${file.path} matches a ${name} pattern inside a code span on a comment line, and the value is provably not a credential — it either spells out its own key or was typed rather than generated. It is NOT reported as a leak. Shown only to confirm the scanner read this line.`, + filePath: file.path, + line: i + 1, + suggestion: 'No action needed. A random value in the same position, or the same value outside a comment, would be reported.', + impactScore: 5, + effort: 'low', + metadata: { credentialType: name, documentedExample: true }, + })) + break + } // Publishable client identifiers, before any severity is assigned — // including the `.env` escalation below, which is what made these // CRITICAL. The file being a committed `.env` is not evidence about a diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 310890c..f84cd92 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -5,6 +5,88 @@ checksums are published at 0 + ? `${approved} changed file(s) are within approved scope; ${inferred.length} more matched scope inferred from this turn and disclosed on the receipt` + : `${inferred.length} changed file(s) matched scope inferred from this turn and disclosed on the receipt; none matched an approved allow root`, + ) } if (failed.length) return { verdict: 'FAILED', reasons: [...failed, ...review] } if (review.length) return { verdict: 'REVIEW_REQUIRED', reasons: review } diff --git a/packages/cli/src/hook-result.ts b/packages/cli/src/hook-result.ts index c8960c0..8c390a6 100644 --- a/packages/cli/src/hook-result.ts +++ b/packages/cli/src/hook-result.ts @@ -135,7 +135,9 @@ export async function writeInternalHookResult( const temporary = `${request.path}.${process.pid}.${randomUUID()}.tmp` let handle: Awaited> | undefined try { + // codetruss-ignore: verified 2026-08-08: request.path passed three containment gates above (absolute+normalized, lexical containment, deterministic attempt location) — this IS the containment implementation handle = await open(temporary, 'wx', 0o600) + // codetruss-ignore: verified 2026-08-08: same containment-implementation site as the line above await handle.writeFile(value, 'utf8') await handle.sync() await handle.close() diff --git a/packages/cli/test/scope-inference.test.ts b/packages/cli/test/scope-inference.test.ts index a2dbb90..8598d00 100644 --- a/packages/cli/test/scope-inference.test.ts +++ b/packages/cli/test/scope-inference.test.ts @@ -297,9 +297,42 @@ describe('inferred scope on the verdict', () => { expect(outcome.verdict).toBe('PASS') expect(outcome.reasons.join('\n')).not.toContain('outside approved scope') + // Leads with the count in scope, not with a zero. "0 changed file(s) are + // within approved scope" was true and read as "nothing was checked". expect(outcome.reasons).toContain( - '0 changed file(s) are within approved scope; 2 more matched scope inferred from this turn and disclosed on the receipt', + '2 changed file(s) matched scope inferred from this turn and disclosed on the receipt; none matched an approved allow root', ) + // The property this test has always been about: inferred scope is in scope, + // and is still never called approved. + expect(outcome.reasons.join('\n')).not.toContain('within approved scope') + }) + + it('never opens with a zero on a repository that has no allow roots at all', () => { + // The first line CodeTruss prints in a repository with no `.codetruss.yml`, + // which is every repository the first time someone runs it. Found by + // installing the published tarball and running `review --staged` on axios. + const { files } = resolve('Add a debugOrigin helper', turn(['lib/helpers/isURLSameOrigin.js'], []), []) + + const outcome = verdictFor(files) + + expect(outcome.verdict).toBe('PASS') + expect(outcome.reasons).toContain( + '1 changed file(s) matched scope inferred from this turn and disclosed on the receipt; none matched an approved allow root', + ) + expect(outcome.reasons.join('\n')).not.toMatch(/\b0 changed file\(s\)/) + }) + + it('still counts the approved ones separately when some were approved', () => { + // The mixed case has to keep reporting both numbers: one file inside the + // repository's own allow root, one reached only by inference. + const allow = ['lib/**'] + const { files } = resolve( + 'Add password reset', + turn(['lib/util.ts', 'src/auth/reset.ts', 'src/auth/tokens.ts'], allow), + allow, + ) + + expect(verdictFor(files).reasons.join('\n')).toContain('1 changed file(s) are within approved scope; 2 more') }) it('still requires review for the file inference refused to cover', () => { diff --git a/public/downloads/codetruss-cli-0.2.58.sbom.cdx.json b/public/downloads/codetruss-cli-0.2.58.sbom.cdx.json new file mode 100644 index 0000000..8ed59b9 --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.58.sbom.cdx.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "serialNumber": "urn:uuid:355e8cdb-e8ea-5775-9034-d86e67172226", + "specVersion": "1.6", + "version": 1, + "metadata": { + "component": { + "type": "application", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.58", + "name": "@codetruss/cli", + "version": "0.2.58", + "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.58" + }, + "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.58", + "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.58.tgz b/public/downloads/codetruss-cli-0.2.58.tgz new file mode 100644 index 0000000..ca0e692 Binary files /dev/null and b/public/downloads/codetruss-cli-0.2.58.tgz differ diff --git a/public/downloads/codetruss-cli-0.2.58.tgz.sha256 b/public/downloads/codetruss-cli-0.2.58.tgz.sha256 new file mode 100644 index 0000000..cdd320a --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.58.tgz.sha256 @@ -0,0 +1 @@ +f69efd07566be17c70be9865e7136d1aea087a976617137e89860791b9ef8d74 codetruss-cli-0.2.58.tgz diff --git a/public/downloads/codetruss-cli-0.2.59.sbom.cdx.json b/public/downloads/codetruss-cli-0.2.59.sbom.cdx.json new file mode 100644 index 0000000..96e7d9a --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.59.sbom.cdx.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "serialNumber": "urn:uuid:0ef05f2f-6531-52bf-8405-dd2f9c013ae4", + "specVersion": "1.6", + "version": 1, + "metadata": { + "component": { + "type": "application", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.59", + "name": "@codetruss/cli", + "version": "0.2.59", + "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.59" + }, + "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.59", + "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.59.tgz b/public/downloads/codetruss-cli-0.2.59.tgz new file mode 100644 index 0000000..813d54d Binary files /dev/null and b/public/downloads/codetruss-cli-0.2.59.tgz differ diff --git a/public/downloads/codetruss-cli-0.2.59.tgz.sha256 b/public/downloads/codetruss-cli-0.2.59.tgz.sha256 new file mode 100644 index 0000000..f88ea8c --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.59.tgz.sha256 @@ -0,0 +1 @@ +8ce2cf3eb0700e3cf7b0cac19bf9e90326e7540b20672ae02806423470704a47 codetruss-cli-0.2.59.tgz diff --git a/public/downloads/codetruss-cli-0.2.60.sbom.cdx.json b/public/downloads/codetruss-cli-0.2.60.sbom.cdx.json new file mode 100644 index 0000000..82e6da4 --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.60.sbom.cdx.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "serialNumber": "urn:uuid:38e747ae-07db-515d-90f5-9eada439ff45", + "specVersion": "1.6", + "version": 1, + "metadata": { + "component": { + "type": "application", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.60", + "name": "@codetruss/cli", + "version": "0.2.60", + "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.60" + }, + "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.60", + "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.60.tgz b/public/downloads/codetruss-cli-0.2.60.tgz new file mode 100644 index 0000000..970604c Binary files /dev/null and b/public/downloads/codetruss-cli-0.2.60.tgz differ diff --git a/public/downloads/codetruss-cli-0.2.60.tgz.sha256 b/public/downloads/codetruss-cli-0.2.60.tgz.sha256 new file mode 100644 index 0000000..a70197d --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.60.tgz.sha256 @@ -0,0 +1 @@ +5afe5499754bf55526f89629a1bdfb40ef30c4a5860c477b385c80ee041b440f codetruss-cli-0.2.60.tgz diff --git a/public/downloads/codetruss-cli-0.2.61.sbom.cdx.json b/public/downloads/codetruss-cli-0.2.61.sbom.cdx.json new file mode 100644 index 0000000..4c17eea --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.61.sbom.cdx.json @@ -0,0 +1,170 @@ +{ + "$schema": "https://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "serialNumber": "urn:uuid:0744463b-fb3a-5cbf-858b-8224ba9c5137", + "specVersion": "1.6", + "version": 1, + "metadata": { + "component": { + "type": "application", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.61", + "name": "@codetruss/cli", + "version": "0.2.61", + "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.61" + }, + "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.61", + "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.61.tgz b/public/downloads/codetruss-cli-0.2.61.tgz new file mode 100644 index 0000000..f701ea9 Binary files /dev/null and b/public/downloads/codetruss-cli-0.2.61.tgz differ diff --git a/public/downloads/codetruss-cli-0.2.61.tgz.sha256 b/public/downloads/codetruss-cli-0.2.61.tgz.sha256 new file mode 100644 index 0000000..6e7ffa4 --- /dev/null +++ b/public/downloads/codetruss-cli-0.2.61.tgz.sha256 @@ -0,0 +1 @@ +b1d2f7c8f016cdade18ab67d9af68b82b1623546d1b221ed2727e5acf158aec6 codetruss-cli-0.2.61.tgz diff --git a/public/downloads/codetruss-cli-latest.json b/public/downloads/codetruss-cli-latest.json index 72cbb43..4400a69 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.57", - "url": "/downloads/codetruss-cli-0.2.57.tgz", + "version": "0.2.61", + "url": "/downloads/codetruss-cli-0.2.61.tgz", "latestUrl": "/downloads/codetruss-cli-latest.tgz", - "sha256": "533bd51c59e88febe5a3a1df88c0fcb3e6966970280017c7b84efb63a421ce9f", - "sbomUrl": "/downloads/codetruss-cli-0.2.57.sbom.cdx.json", - "sbomSha256": "039d38250847d386b1249bcb6340c913527fab79f28979c52ef77edd3972e45b", + "sha256": "b1d2f7c8f016cdade18ab67d9af68b82b1623546d1b221ed2727e5acf158aec6", + "sbomUrl": "/downloads/codetruss-cli-0.2.61.sbom.cdx.json", + "sbomSha256": "78ec407ebdb13be8025f6cca778107faf6a1dc320ecf2a9bad67948cca1662b7", "node": ">=20.9.0", "repository": "https://github.com/CodeTruss/codetruss-cli", - "releaseUrl": "https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.57", - "attestationCommand": "gh attestation verify codetruss-cli-0.2.57.tgz --repo CodeTruss/codetruss-cli" + "releaseUrl": "https://github.com/CodeTruss/codetruss-cli/releases/tag/v0.2.61", + "attestationCommand": "gh attestation verify codetruss-cli-0.2.61.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 2ea88bb..4c17eea 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:57bb9b7c-36c4-5760-89d4-7738f3e24452", + "serialNumber": "urn:uuid:0744463b-fb3a-5cbf-858b-8224ba9c5137", "specVersion": "1.6", "version": 1, "metadata": { "component": { "type": "application", - "bom-ref": "pkg:npm/%40codetruss/cli@0.2.57", + "bom-ref": "pkg:npm/%40codetruss/cli@0.2.61", "name": "@codetruss/cli", - "version": "0.2.57", + "version": "0.2.61", "description": "Local-first scope, quality, and verification receipts for coding agents", "licenses": [ { @@ -18,7 +18,7 @@ } } ], - "purl": "pkg:npm/%40codetruss/cli@0.2.57" + "purl": "pkg:npm/%40codetruss/cli@0.2.61" }, "properties": [ { @@ -139,7 +139,7 @@ "dependsOn": [] }, { - "ref": "pkg:npm/%40codetruss/cli@0.2.57", + "ref": "pkg:npm/%40codetruss/cli@0.2.61", "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 6dcbc7c..f701ea9 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 7b21401..73e92fa 100644 --- a/public/downloads/codetruss-cli-latest.tgz.sha256 +++ b/public/downloads/codetruss-cli-latest.tgz.sha256 @@ -1 +1 @@ -533bd51c59e88febe5a3a1df88c0fcb3e6966970280017c7b84efb63a421ce9f codetruss-cli-latest.tgz +b1d2f7c8f016cdade18ab67d9af68b82b1623546d1b221ed2727e5acf158aec6 codetruss-cli-latest.tgz diff --git a/release-reference.json b/release-reference.json index 2211281..5622d99 100644 --- a/release-reference.json +++ b/release-reference.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, - "version": "0.2.57", - "websiteArchive": "https://codetruss.com/downloads/codetruss-cli-0.2.57.tgz", - "archiveSha256": "533bd51c59e88febe5a3a1df88c0fcb3e6966970280017c7b84efb63a421ce9f", - "sbomSha256": "039d38250847d386b1249bcb6340c913527fab79f28979c52ef77edd3972e45b", - "bundleSha256": "7e874ebe02a8e968edb360b86ab4aa21909ee7fe273a1ef776c34703907f87f9" + "version": "0.2.61", + "websiteArchive": "https://codetruss.com/downloads/codetruss-cli-0.2.61.tgz", + "archiveSha256": "b1d2f7c8f016cdade18ab67d9af68b82b1623546d1b221ed2727e5acf158aec6", + "sbomSha256": "78ec407ebdb13be8025f6cca778107faf6a1dc320ecf2a9bad67948cca1662b7", + "bundleSha256": "c135a12664418232c697430a96ab2d168bac4fb3c87159265f9ec1fc2d75ab38" }