Skip to content

Commit 2814140

Browse files
authored
fix(security): GA-022/028 checksum fail-closed + version override (#11)
* fix(security): GA-022/028 checksum fail-closed + version override GA-022: Default checksum verification to fail-closed - Invert default: checksum now required unless CAPISCIO_SKIP_CHECKSUM=true - Replace opt-in CAPISCIO_REQUIRE_CHECKSUM with opt-out CAPISCIO_SKIP_CHECKSUM - Fail with actionable error message if checksums unavailable GA-028: Add capiscio-version input to action.yml - Users can now pin CapiscIO Core version: capiscio-version: '2.5.0' - Defaults to 2.6.0 - Read from action input in src/index.ts Rebuild dist/index.js with all changes. * fix: skip checksum in CI test (no checksums.txt in releases yet) Releases don't include checksums.txt yet. With fail-closed default, the sample agent card test fails on checksum verification.
1 parent 320d544 commit 2814140

8 files changed

Lines changed: 47 additions & 39 deletions

File tree

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ jobs:
2929
with:
3030
agent-card: './test-agent.json'
3131
# Use local file to avoid network issues in CI
32+
env:
33+
# No releases currently include checksums.txt — skip verification in CI
34+
CAPISCIO_SKIP_CHECKSUM: 'true'
3235

3336
- name: Display outputs
3437
run: |

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ inputs:
3737
required: false
3838
default: 'false'
3939

40+
capiscio-version:
41+
description: 'Version of CapiscIO Core to use for validation'
42+
required: false
43+
default: '2.6.0'
44+
4045
outputs:
4146
result:
4247
description: 'Validation result: "passed" or "failed"'

dist/checksum.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export declare function fetchText(url: string): Promise<string>;
22
export declare function computeSHA256(filePath: string): Promise<string>;
33
export interface ChecksumOptions {
44
version: string;
5-
requireChecksum: boolean;
5+
skipChecksum: boolean;
66
warn: (msg: string) => void;
77
info: (msg: string) => void;
88
}

dist/checksum.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28287,22 +28287,22 @@ async function verifyChecksum(downloadedFile, binaryName, options) {
2828728287
}
2828828288
}
2828928289
catch {
28290-
if (options.requireChecksum) {
28291-
fs.rmSync(downloadedFile, { force: true });
28292-
throw new Error('Checksum verification required (CAPISCIO_REQUIRE_CHECKSUM=true) ' +
28293-
'but checksums.txt is not available. Cannot verify binary integrity.');
28290+
if (options.skipChecksum) {
28291+
options.warn('Could not fetch checksums.txt. Skipping integrity verification (CAPISCIO_SKIP_CHECKSUM=true).');
28292+
return;
2829428293
}
28295-
options.warn('Could not fetch checksums.txt. Skipping integrity verification.');
28296-
return;
28294+
fs.rmSync(downloadedFile, { force: true });
28295+
throw new Error('Checksum verification failed: checksums.txt is not available. ' +
28296+
'Cannot verify binary integrity. Set CAPISCIO_SKIP_CHECKSUM=true to bypass.');
2829728297
}
2829828298
if (!expectedHash) {
28299-
if (options.requireChecksum) {
28300-
fs.rmSync(downloadedFile, { force: true });
28301-
throw new Error(`Checksum verification required (CAPISCIO_REQUIRE_CHECKSUM=true) ` +
28302-
`but asset ${binaryName} not found in checksums.txt.`);
28299+
if (options.skipChecksum) {
28300+
options.warn(`Asset ${binaryName} not found in checksums.txt. Skipping verification (CAPISCIO_SKIP_CHECKSUM=true).`);
28301+
return;
2830328302
}
28304-
options.warn(`Asset ${binaryName} not found in checksums.txt. Skipping verification.`);
28305-
return;
28303+
fs.rmSync(downloadedFile, { force: true });
28304+
throw new Error(`Checksum verification failed: asset ${binaryName} not found in checksums.txt. ` +
28305+
`Set CAPISCIO_SKIP_CHECKSUM=true to bypass.`);
2830628306
}
2830728307
const actualHash = await computeSHA256(downloadedFile);
2830828308
if (actualHash !== expectedHash) {
@@ -28377,7 +28377,7 @@ const path = __importStar(__nccwpck_require__(6928));
2837728377
const fs = __importStar(__nccwpck_require__(9896));
2837828378
const validation_1 = __nccwpck_require__(4344);
2837928379
const checksum_1 = __nccwpck_require__(4596);
28380-
const CAPISCIO_VERSION = '2.6.0';
28380+
const CAPISCIO_VERSION = core.getInput('capiscio-version') || '2.6.0';
2838128381
async function setupCapiscio() {
2838228382
// Determine OS and Arch
2838328383
const platform = os.platform();
@@ -28404,10 +28404,10 @@ async function setupCapiscio() {
2840428404
// Download
2840528405
const downloadPath = await tc.downloadTool(downloadUrl);
2840628406
// Verify checksum before making executable
28407-
const requireChecksum = ['1', 'true', 'yes'].includes((process.env.CAPISCIO_REQUIRE_CHECKSUM ?? '').toLowerCase());
28407+
const skipChecksum = ['1', 'true', 'yes'].includes((process.env.CAPISCIO_SKIP_CHECKSUM ?? '').toLowerCase());
2840828408
await (0, checksum_1.verifyChecksum)(downloadPath, binaryName, {
2840928409
version: CAPISCIO_VERSION,
28410-
requireChecksum,
28410+
skipChecksum,
2841128411
warn: (msg) => core.warning(msg),
2841228412
info: (msg) => core.info(msg),
2841328413
});

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/checksum.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export async function computeSHA256(filePath: string): Promise<string> {
3636

3737
export interface ChecksumOptions {
3838
version: string;
39-
requireChecksum: boolean;
39+
skipChecksum: boolean;
4040
warn: (msg: string) => void;
4141
info: (msg: string) => void;
4242
}
@@ -60,27 +60,27 @@ export async function verifyChecksum(
6060
}
6161
}
6262
} catch {
63-
if (options.requireChecksum) {
64-
fs.rmSync(downloadedFile, { force: true });
65-
throw new Error(
66-
'Checksum verification required (CAPISCIO_REQUIRE_CHECKSUM=true) ' +
67-
'but checksums.txt is not available. Cannot verify binary integrity.'
68-
);
63+
if (options.skipChecksum) {
64+
options.warn('Could not fetch checksums.txt. Skipping integrity verification (CAPISCIO_SKIP_CHECKSUM=true).');
65+
return;
6966
}
70-
options.warn('Could not fetch checksums.txt. Skipping integrity verification.');
71-
return;
67+
fs.rmSync(downloadedFile, { force: true });
68+
throw new Error(
69+
'Checksum verification failed: checksums.txt is not available. ' +
70+
'Cannot verify binary integrity. Set CAPISCIO_SKIP_CHECKSUM=true to bypass.'
71+
);
7272
}
7373

7474
if (!expectedHash) {
75-
if (options.requireChecksum) {
76-
fs.rmSync(downloadedFile, { force: true });
77-
throw new Error(
78-
`Checksum verification required (CAPISCIO_REQUIRE_CHECKSUM=true) ` +
79-
`but asset ${binaryName} not found in checksums.txt.`
80-
);
75+
if (options.skipChecksum) {
76+
options.warn(`Asset ${binaryName} not found in checksums.txt. Skipping verification (CAPISCIO_SKIP_CHECKSUM=true).`);
77+
return;
8178
}
82-
options.warn(`Asset ${binaryName} not found in checksums.txt. Skipping verification.`);
83-
return;
79+
fs.rmSync(downloadedFile, { force: true });
80+
throw new Error(
81+
`Checksum verification failed: asset ${binaryName} not found in checksums.txt. ` +
82+
`Set CAPISCIO_SKIP_CHECKSUM=true to bypass.`
83+
);
8484
}
8585

8686
const actualHash = await computeSHA256(downloadedFile);

src/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from './validation';
1313
import { verifyChecksum } from './checksum';
1414

15-
const CAPISCIO_VERSION = '2.6.0';
15+
const CAPISCIO_VERSION = core.getInput('capiscio-version') || '2.6.0';
1616

1717
async function setupCapiscio(): Promise<string> {
1818
// Determine OS and Arch
@@ -39,12 +39,12 @@ async function setupCapiscio(): Promise<string> {
3939
const downloadPath = await tc.downloadTool(downloadUrl);
4040

4141
// Verify checksum before making executable
42-
const requireChecksum = ['1', 'true', 'yes'].includes(
43-
(process.env.CAPISCIO_REQUIRE_CHECKSUM ?? '').toLowerCase()
42+
const skipChecksum = ['1', 'true', 'yes'].includes(
43+
(process.env.CAPISCIO_SKIP_CHECKSUM ?? '').toLowerCase()
4444
);
4545
await verifyChecksum(downloadPath, binaryName, {
4646
version: CAPISCIO_VERSION,
47-
requireChecksum,
47+
skipChecksum,
4848
warn: (msg) => core.warning(msg),
4949
info: (msg) => core.info(msg),
5050
});

0 commit comments

Comments
 (0)