Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions bounty-submission-quarantine-guard/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const fs = require("fs");
const path = require("path");
const { submissionBatch } = require("./sample-data");
const { evaluateBatch } = require("./index");

const reportsDir = path.join(__dirname, "reports");
fs.mkdirSync(reportsDir, { recursive: true });

const report = evaluateBatch(submissionBatch);
fs.writeFileSync(path.join(reportsDir, "submission-quarantine-report.json"), `${JSON.stringify(report, null, 2)}\n`);

const markdown = [
"# Scientific Bounty Submission Quarantine Report",
"",
`Batch: ${report.batchId}`,
`Generated: ${report.generatedAt}`,
"",
"## Summary",
"",
`- Submissions evaluated: ${report.summary.total}`,
`- Released to review: ${report.summary["release-to-review"] || 0}`,
`- Quarantined: ${report.summary["quarantine-submission"] || 0}`,
`- Findings: ${report.summary.findingCount}`,
"",
"## Decisions",
"",
...report.submissions.flatMap((item) => [
`### ${item.id}`,
"",
`- Challenge: ${item.challengeId}`,
`- Team: ${item.teamId}`,
`- Decision: ${item.decision}`,
`- Findings: ${item.findings.length ? item.findings.join("; ") : "none"}`,
`- Actions: ${item.actions.join("; ")}`,
""
])
].join("\n").trim();

fs.writeFileSync(path.join(reportsDir, "submission-quarantine-report.md"), `${markdown}\n`);

const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="960" height="540" viewBox="0 0 960 540">
<rect width="960" height="540" fill="#f8fafc"/>
<text x="48" y="64" font-family="Arial" font-size="28" font-weight="700" fill="#172033">Submission Quarantine Guard</text>
<text x="48" y="102" font-family="Arial" font-size="16" fill="#4f5d75">Scientific bounty package safety before sponsor access</text>
${report.submissions.map((item, index) => {
const y = 150 + index * 82;
const color = item.decision === "release-to-review" ? "#047857" : "#b45309";
return `<rect x="48" y="${y - 34}" width="864" height="58" rx="6" fill="#ffffff" stroke="#d7dce6"/>
<text x="72" y="${y - 8}" font-family="Arial" font-size="18" font-weight="700" fill="#172033">${item.id}</text>
<text x="72" y="${y + 16}" font-family="Arial" font-size="14" fill="${color}">${item.decision}</text>
<text x="300" y="${y + 16}" font-family="Arial" font-size="14" fill="#4f5d75">${item.teamId}, ${item.findings.length} finding(s)</text>`;
}).join("\n ")}
</svg>
`;
fs.writeFileSync(path.join(reportsDir, "summary.svg"), svg);
console.log(JSON.stringify(report.summary, null, 2));
38 changes: 38 additions & 0 deletions bounty-submission-quarantine-guard/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
function evaluateSubmission(submission) {
const findings = [];

if (!submission.manifestComplete) findings.push("submission package manifest is incomplete");
if (submission.artifactHashes.length === 0) findings.push("submission artifacts are missing hashes");
if (submission.unsafeFlags.length > 0) findings.push(`unsafe artifact flags: ${submission.unsafeFlags.join(", ")}`);
if (submission.sponsorVisible && findings.length > 0) findings.push("sponsor visibility is enabled before quarantine clearance");
if (!submission.reviewerPreview) findings.push("reviewer-safe preview is missing");
if (submission.ipStatement === "missing") findings.push("IP handoff statement is missing");

const decision = findings.length === 0 ? "release-to-review" : "quarantine-submission";
const actions = decision === "release-to-review"
? ["release package to reviewer queue", "keep sponsor access gated until award decision"]
: ["quarantine package", "disable sponsor visibility", "request manifest and safety remediation"];

return {
id: submission.id,
challengeId: submission.challengeId,
teamId: submission.teamId,
decision,
findings,
actions
};
}

function evaluateBatch(batch) {
const submissions = batch.submissions.map(evaluateSubmission);
const summary = submissions.reduce((acc, submission) => {
acc.total += 1;
acc[submission.decision] = (acc[submission.decision] || 0) + 1;
acc.findingCount += submission.findings.length;
return acc;
}, { total: 0, findingCount: 0 });

return { batchId: batch.id, generatedAt: batch.generatedAt, summary, submissions };
}

module.exports = { evaluateSubmission, evaluateBatch };
33 changes: 33 additions & 0 deletions bounty-submission-quarantine-guard/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Scientific Bounty Submission Quarantine Guard

This module adds a focused quarantine layer for the Scientific Bounty System. It decides whether solver submissions are safe and complete enough to reach reviewers or sponsors.

It is intentionally separate from challenge intake, scoring and arbitration, payout routing, evidence freeze, anonymous review packets, prequalification, data-use agreements, closeout, reviewer workload, deadline fairness, and package security scanning. This guard handles submission quarantine and sponsor-visibility gating.

## What It Checks

- Package manifest completeness
- Artifact hash coverage
- Unsafe artifact flags such as executable binaries or macro-enabled documents
- Sponsor visibility before clearance
- Reviewer-safe preview availability
- IP handoff statement presence

## Demo

Run:

```bash
node bounty-submission-quarantine-guard/test.js
node bounty-submission-quarantine-guard/demo.js
node bounty-submission-quarantine-guard/render-video.js
```

Generated artifacts:

- `reports/submission-quarantine-report.json`
- `reports/submission-quarantine-report.md`
- `reports/summary.svg`
- `reports/demo.mp4`

All data is synthetic. The module does not execute solver files, call storage providers, expose sponsor data, process payment details, use credentials, or contact SCIBASE production services.
38 changes: 38 additions & 0 deletions bounty-submission-quarantine-guard/render-video.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const fs = require("fs");
const path = require("path");
const { spawnSync } = require("child_process");

const reportsDir = path.join(__dirname, "reports");
fs.mkdirSync(reportsDir, { recursive: true });
const width = 960;
const height = 540;
const ppm = path.join(reportsDir, "demo-frame.ppm");
const mp4 = path.join(reportsDir, "demo.mp4");

function pixel(x, y) {
if (y < 112) return [23, 32, 51];
if (x > 46 && x < 914 && y > 126 && y < 188) return [255, 255, 255];
if (x > 46 && x < 914 && y > 210 && y < 272) return [255, 255, 255];
if (x > 46 && x < 914 && y > 294 && y < 356) return [255, 255, 255];
if (x > 46 && x < 914 && y > 378 && y < 440) return [255, 255, 255];
if (x > 64 && x < 238 && y > 140 && y < 174) return [4, 120, 87];
if (x > 64 && x < 238 && y > 224 && y < 258) return [180, 83, 9];
if (x > 64 && x < 238 && y > 308 && y < 342) return [180, 83, 9];
if (x > 64 && x < 238 && y > 392 && y < 426) return [4, 120, 87];
return [248, 250, 252];
}
const header = `P6\n${width} ${height}\n255\n`;
const body = Buffer.alloc(width * height * 3);
for (let y = 0; y < height; y += 1) {
for (let x = 0; x < width; x += 1) {
const offset = (y * width + x) * 3;
const [r, g, b] = pixel(x, y);
body[offset] = r;
body[offset + 1] = g;
body[offset + 2] = b;
}
}
fs.writeFileSync(ppm, Buffer.concat([Buffer.from(header), body]));
const result = spawnSync("ffmpeg", ["-y", "-loop", "1", "-framerate", "24", "-i", ppm, "-t", "5", "-vf", "format=yuv420p", "-movflags", "+faststart", mp4], { stdio: "inherit" });
if (result.status !== 0) throw new Error("ffmpeg failed to render demo video");
console.log(mp4);
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"batchId": "bounty-submission-quarantine-2026-05-29",
"generatedAt": "2026-05-29T14:34:00.000Z",
"summary": {
"total": 4,
"findingCount": 7,
"release-to-review": 2,
"quarantine-submission": 2
},
"submissions": [
{
"id": "sub-1",
"challengeId": "challenge-bio-17",
"teamId": "team-alpha",
"decision": "release-to-review",
"findings": [],
"actions": [
"release package to reviewer queue",
"keep sponsor access gated until award decision"
]
},
{
"id": "sub-2",
"challengeId": "challenge-ml-04",
"teamId": "team-beta",
"decision": "quarantine-submission",
"findings": [
"submission package manifest is incomplete",
"unsafe artifact flags: macro-enabled-document",
"sponsor visibility is enabled before quarantine clearance",
"reviewer-safe preview is missing",
"IP handoff statement is missing"
],
"actions": [
"quarantine package",
"disable sponsor visibility",
"request manifest and safety remediation"
]
},
{
"id": "sub-3",
"challengeId": "challenge-climate-09",
"teamId": "team-gamma",
"decision": "quarantine-submission",
"findings": [
"submission artifacts are missing hashes",
"unsafe artifact flags: executable-binary"
],
"actions": [
"quarantine package",
"disable sponsor visibility",
"request manifest and safety remediation"
]
},
{
"id": "sub-4",
"challengeId": "challenge-quantum-02",
"teamId": "team-delta",
"decision": "release-to-review",
"findings": [],
"actions": [
"release package to reviewer queue",
"keep sponsor access gated until award decision"
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Scientific Bounty Submission Quarantine Report

Batch: bounty-submission-quarantine-2026-05-29
Generated: 2026-05-29T14:34:00.000Z

## Summary

- Submissions evaluated: 4
- Released to review: 2
- Quarantined: 2
- Findings: 7

## Decisions

### sub-1

- Challenge: challenge-bio-17
- Team: team-alpha
- Decision: release-to-review
- Findings: none
- Actions: release package to reviewer queue; keep sponsor access gated until award decision

### sub-2

- Challenge: challenge-ml-04
- Team: team-beta
- Decision: quarantine-submission
- Findings: submission package manifest is incomplete; unsafe artifact flags: macro-enabled-document; sponsor visibility is enabled before quarantine clearance; reviewer-safe preview is missing; IP handoff statement is missing
- Actions: quarantine package; disable sponsor visibility; request manifest and safety remediation

### sub-3

- Challenge: challenge-climate-09
- Team: team-gamma
- Decision: quarantine-submission
- Findings: submission artifacts are missing hashes; unsafe artifact flags: executable-binary
- Actions: quarantine package; disable sponsor visibility; request manifest and safety remediation

### sub-4

- Challenge: challenge-quantum-02
- Team: team-delta
- Decision: release-to-review
- Findings: none
- Actions: release package to reviewer queue; keep sponsor access gated until award decision
21 changes: 21 additions & 0 deletions bounty-submission-quarantine-guard/reports/summary.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions bounty-submission-quarantine-guard/sample-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const submissionBatch = {
id: "bounty-submission-quarantine-2026-05-29",
generatedAt: "2026-05-29T14:34:00.000Z",
submissions: [
{
id: "sub-1",
challengeId: "challenge-bio-17",
teamId: "team-alpha",
manifestComplete: true,
artifactHashes: ["sha256:aa01", "sha256:bb02"],
unsafeFlags: [],
sponsorVisible: false,
reviewerPreview: true,
ipStatement: "solver-retains-until-paid"
},
{
id: "sub-2",
challengeId: "challenge-ml-04",
teamId: "team-beta",
manifestComplete: false,
artifactHashes: ["sha256:cc03"],
unsafeFlags: ["macro-enabled-document"],
sponsorVisible: true,
reviewerPreview: false,
ipStatement: "missing"
},
{
id: "sub-3",
challengeId: "challenge-climate-09",
teamId: "team-gamma",
manifestComplete: true,
artifactHashes: [],
unsafeFlags: ["executable-binary"],
sponsorVisible: false,
reviewerPreview: true,
ipStatement: "open-license-after-award"
},
{
id: "sub-4",
challengeId: "challenge-quantum-02",
teamId: "team-delta",
manifestComplete: true,
artifactHashes: ["sha256:dd04"],
unsafeFlags: [],
sponsorVisible: false,
reviewerPreview: true,
ipStatement: "sponsor-transfer-on-payout"
}
]
};

module.exports = { submissionBatch };
20 changes: 20 additions & 0 deletions bounty-submission-quarantine-guard/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const assert = require("assert");
const { submissionBatch } = require("./sample-data");
const { evaluateBatch } = require("./index");

const report = evaluateBatch(submissionBatch);

assert.strictEqual(report.summary.total, 4);
assert.strictEqual(report.summary["release-to-review"], 2);
assert.strictEqual(report.summary["quarantine-submission"], 2);

const beta = report.submissions.find((item) => item.id === "sub-2");
assert(beta.findings.some((finding) => finding.includes("manifest")));
assert(beta.findings.some((finding) => finding.includes("sponsor visibility")));
assert(beta.findings.some((finding) => finding.includes("IP handoff")));

const gamma = report.submissions.find((item) => item.id === "sub-3");
assert(gamma.findings.some((finding) => finding.includes("missing hashes")));
assert(gamma.findings.some((finding) => finding.includes("executable-binary")));

console.log("bounty-submission-quarantine-guard tests passed");