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
69 changes: 69 additions & 0 deletions scripts/validate-codebounty-issue-96.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Validate the CodeBounty issue #96 external-sponsor fixture.

The fixture is intentionally dependency-free so maintainers can verify the
GitHub-side bounty metadata without installing project tooling.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path


EXPECTED = {
"issue_number": 96,
"amount_usd": 50,
"required_linkage": "fixes #96",
}


def fail(message: str) -> None:
print(f"FAIL: {message}", file=sys.stderr)
raise SystemExit(1)


def main(path_arg: str) -> None:
path = Path(path_arg)
if not path.is_file():
fail(f"fixture does not exist: {path}")

data = json.loads(path.read_text(encoding="utf-8"))
issue = data.get("issue") or {}
bounty = data.get("bounty") or {}
submission = data.get("submission") or {}

if issue.get("number") != EXPECTED["issue_number"]:
fail(f"issue number must be {EXPECTED['issue_number']}")
if "CodeBountyOrg/BountyTestRepository/issues/96" not in issue.get("url", ""):
fail("issue URL must point to CodeBountyOrg/BountyTestRepository#96")
if issue.get("state") != "open":
fail("fixture should record the issue as open at validation time")
if "💰 Bounty Available" not in issue.get("labels", []):
fail("fixture should preserve the public bounty label")

if bounty.get("amount_usd") != EXPECTED["amount_usd"]:
fail(f"bounty amount must be ${EXPECTED['amount_usd']}")
if not bounty.get("application_required"):
fail("CodeBounty application requirement must stay explicit")
if bounty.get("verified_payable") is not False:
fail("verified_payable must remain false until platform/maintainer acceptance is proven")
if bounty.get("required_pr_linkage", "").lower() != EXPECTED["required_linkage"]:
fail("required PR linkage must be fixes #96")

if submission.get("expected_pr_body_token") != "Fixes #96":
fail("PR body token should be recorded with GitHub-close syntax casing")
if "does not assert payout eligibility" not in submission.get("claim_boundary", ""):
fail("claim boundary must prevent overclaiming payout status")

print(
"PASS issue=96 amount_usd=50 linkage='Fixes #96' "
"verified_payable=false application_required=true"
)


if __name__ == "__main__":
if len(sys.argv) != 2:
fail("usage: validate-codebounty-issue-96.py <fixture.json>")
main(sys.argv[1])
25 changes: 25 additions & 0 deletions test-fixtures/codebounty-issue-96-external-sponsor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"issue": {
"number": 96,
"title": "test issue creation from external sponsor #2 apr 15",
"url": "https://github.com/CodeBountyOrg/BountyTestRepository/issues/96",
"body": "test description",
"state": "open",
"labels": ["💰 Bounty Available"]
},
"bounty": {
"source": "CodeBounty bot comment",
"amount_usd": 50,
"announcement_url": "https://github.com/CodeBountyOrg/BountyTestRepository/issues/96#issuecomment-2808189095",
"application_required": true,
"required_pr_linkage": "fixes #96",
"verified_payable": false,
"payout_blocker": "CodeBounty platform application and maintainer acceptance are not verified from GitHub alone."
},
"submission": {
"artifact": "test-fixtures/codebounty-issue-96-external-sponsor.json",
"validator": "scripts/validate-codebounty-issue-96.py",
"expected_pr_body_token": "Fixes #96",
"claim_boundary": "This fixture validates the public GitHub-side bounty metadata only; it does not assert payout eligibility."
}
}