feat: add sigstore-verify-rs
This commit is contained in:
1
sigstore-verify-ts/hello.txt
Normal file
1
sigstore-verify-ts/hello.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
hello hatter 2025
|
||||||
145
sigstore-verify-ts/main.ts
Executable file
145
sigstore-verify-ts/main.ts
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env -S deno run --allow-env --allow-run --allow-read
|
||||||
|
|
||||||
|
import {parseArgs} from "jsr:@std/cli/parse-args";
|
||||||
|
|
||||||
|
// Reference:
|
||||||
|
// * https://docs.deno.com/api/deno/~/Deno.Command
|
||||||
|
// * https://docs.deno.com/examples/command_line_arguments/
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "format": "rekor-attest-v1",
|
||||||
|
// "files": [
|
||||||
|
// {
|
||||||
|
// "filename": "example.rs",
|
||||||
|
// "rekorId": "xxxxxxxxxxxxxxxxx"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get from url or rekor-cli
|
||||||
|
// const REKOR_ENTRY_URL = "https://rekor.sigstore.dev/api/v1/log/entries/${UUID}";
|
||||||
|
|
||||||
|
// ----- CONFIG -----
|
||||||
|
interface RekorAttest {
|
||||||
|
format: string;
|
||||||
|
files: Array<RekorAttestFile>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorAttestFile {
|
||||||
|
filename: string;
|
||||||
|
rekorId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- REKOR RECORD -----
|
||||||
|
interface RekorRecord {
|
||||||
|
Attestation: string;
|
||||||
|
AttestationType: string;
|
||||||
|
Body: RekorRecordBody;
|
||||||
|
LogIndex: number;
|
||||||
|
IntegratedTime: number;
|
||||||
|
UUID: number;
|
||||||
|
LogID: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorRecordBody {
|
||||||
|
RekordObj: RekorRecordBodyRekordObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorRecordBodyRekordObj {
|
||||||
|
data: RekorRecordBodyRekordObjData;
|
||||||
|
signature: RekorRecordBodyRekordObjSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorRecordBodyRekordObjData {
|
||||||
|
hash: RekorRecordHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorRecordHash {
|
||||||
|
algorithm: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorRecordBodyRekordObjSignature {
|
||||||
|
content: string;
|
||||||
|
format: string;
|
||||||
|
publicKey: RekorRecordPublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RekorRecordPublicKey {
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadAttest(filename: string): Promise<RekorAttest> {
|
||||||
|
const attest = await Deno.readTextFile(filename);
|
||||||
|
return JSON.parse(attest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchRekorViaCli(uuid: string): RekorRecord {
|
||||||
|
if (isStringEmpty(uuid)) {
|
||||||
|
throw "Rekor UUID is empty."
|
||||||
|
}
|
||||||
|
const command = new Deno.Command("rekor-cli", {
|
||||||
|
args: [
|
||||||
|
"get",
|
||||||
|
"--format",
|
||||||
|
"json",
|
||||||
|
"--uuid",
|
||||||
|
uuid
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const {code, stdout, stderr} = command.outputSync();
|
||||||
|
if (code !== 0) {
|
||||||
|
console.error(`Execute command rekor-cli failed:
|
||||||
|
code: ${code}
|
||||||
|
stdout: ${new TextDecoder().decode(stdout)}
|
||||||
|
stderr: ${new TextDecoder().decode(stderr)}`);
|
||||||
|
throw `Execute command rekor-cli failed, code: ${code}`
|
||||||
|
}
|
||||||
|
const rekorBody = new TextDecoder().decode(stdout);
|
||||||
|
return JSON.parse(rekorBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStringEmpty(str: string): boolean {
|
||||||
|
return str === null || str === undefined || str == "";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Args {
|
||||||
|
help: boolean;
|
||||||
|
attest?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseToArgs(): Args {
|
||||||
|
return parseArgs(Deno.args, {
|
||||||
|
boolean: ["help"],
|
||||||
|
string: ["attest"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyFile(attestFile: RekorAttestFile) {
|
||||||
|
const rekorRecord = fetchRekorViaCli(attestFile.rekorId);
|
||||||
|
console.log(rekorRecord);
|
||||||
|
// TODO ...
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = parseToArgs();
|
||||||
|
if (args.help) {
|
||||||
|
console.log(`sigstore-verify.ts - sigstore verify cli
|
||||||
|
|
||||||
|
sigstore-verify.ts [--attest sigstore-attest.json]
|
||||||
|
`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let attestFileName = args.attest || "sigstore-attest.json";
|
||||||
|
let attest = await loadAttest(attestFileName);
|
||||||
|
if (attest.format !== "rekor-attest-v1") {
|
||||||
|
throw `Bad rekor attest file format: ${attest.format}`;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < attest.files.length; i++) {
|
||||||
|
const attestFile = attest.files[i];
|
||||||
|
console.log(`Process file: ${attestFile.filename} [${i + 1} / ${attest.files.length}]`);
|
||||||
|
await verifyFile(attestFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await main();
|
||||||
9
sigstore-verify-ts/sigstore-attest.json
Normal file
9
sigstore-verify-ts/sigstore-attest.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"format": "rekor-attest-v1",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"filename": "hello.txt",
|
||||||
|
"rekorId": "108e9186e8c5677ab315931b32e40e6af1a5e3267f2a1e2660e15b6604406d59f6a0d8009e6839c1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user