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