Prefill world-class submission artifact hashes
This commit is contained in:
@@ -154,6 +154,8 @@ python3 scripts/yao.py world-class-evidence .
|
||||
SUBMISSIONS_DIR="${SUBMISSIONS_DIR:-evidence/world_class/submissions}"
|
||||
python3 scripts/yao.py world-class-preflight . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR"
|
||||
# Alternative: prefill artifact SHA-256 digests while keeping drafts template-only.
|
||||
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR" --prefill-artifacts
|
||||
python3 scripts/yao.py world-class-intake . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
python3 scripts/yao.py world-class-submission-review . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
python3 scripts/yao.py world-class-ledger . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
|
||||
@@ -10,6 +10,8 @@ Run:
|
||||
SUBMISSIONS_DIR="${SUBMISSIONS_DIR:-evidence/world_class/submissions}"
|
||||
python3 scripts/yao.py world-class-preflight . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR"
|
||||
# Alternative: prefill artifact SHA-256 digests while keeping drafts template-only.
|
||||
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR" --prefill-artifacts
|
||||
python3 scripts/yao.py world-class-intake . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
python3 scripts/yao.py world-class-submission-review . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
python3 scripts/yao.py world-class-ledger . --submissions-dir "$SUBMISSIONS_DIR"
|
||||
@@ -28,7 +30,7 @@ Run `world-class-preflight` before assigning external or human work. It checks l
|
||||
|
||||
The generated intake report also includes an `operator_checklist` for each pending evidence item. Use it to find the template path, target submission path, preparation command, validation command, required provenance, success checks, and privacy boundary before asking a reviewer or external operator to submit evidence.
|
||||
|
||||
The submission kit command creates editable JSON drafts plus a local README for an external operator or human reviewer. Those drafts keep `template_only: true` and do not count as evidence until the real run or review exists, the packet is edited truthfully, every artifact ref points to a local aggregate evidence file with a matching `sha256`, and `world-class-intake` validates it.
|
||||
The submission kit command creates editable JSON drafts plus a local README for an external operator or human reviewer. Use `--prefill-artifacts` when you want the kit to insert SHA-256 digests for currently available local aggregate artifacts. Prefill is operator convenience only: those drafts still keep `template_only: true` and do not count as evidence until the real run or review exists, the packet is edited truthfully, every artifact ref points to a local aggregate evidence file with a matching `sha256`, and `world-class-intake` validates it.
|
||||
|
||||
The submission review command renders a read-only queue that compares valid packets with the source evidence checks and current ledger state. It is for reviewer triage only; it does not accept evidence or make the world-class claim true.
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import shlex
|
||||
import shutil
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -59,12 +58,60 @@ def template_result_by_key(intake: dict[str, Any]) -> dict[str, dict[str, Any]]:
|
||||
return {str(item.get("evidence_key")): item for item in intake.get("templates", [])}
|
||||
|
||||
|
||||
def artifact_rows_by_key_and_path(rows: list[dict[str, Any]]) -> dict[tuple[str, str], dict[str, Any]]:
|
||||
ready: dict[tuple[str, str], dict[str, Any]] = {}
|
||||
for row in rows:
|
||||
key = str(row.get("evidence_key", ""))
|
||||
path = str(row.get("path", ""))
|
||||
if key and path and row.get("artifact_ref_ready"):
|
||||
ready[(key, path)] = row
|
||||
return ready
|
||||
|
||||
|
||||
def load_template_payload(path: Path, errors: list[str]) -> dict[str, Any] | None:
|
||||
try:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
except json.JSONDecodeError:
|
||||
errors.append("template file is not valid JSON")
|
||||
return None
|
||||
return payload if isinstance(payload, dict) else None
|
||||
|
||||
|
||||
def prefill_artifact_refs(
|
||||
payload: dict[str, Any],
|
||||
evidence_key: str,
|
||||
ready_rows: dict[tuple[str, str], dict[str, Any]],
|
||||
) -> dict[str, int]:
|
||||
refs = payload.get("artifact_refs", [])
|
||||
stats = {
|
||||
"prefilled_artifact_ref_count": 0,
|
||||
"unfilled_artifact_ref_count": 0,
|
||||
}
|
||||
if not isinstance(refs, list):
|
||||
return stats
|
||||
for ref in refs:
|
||||
if not isinstance(ref, dict):
|
||||
stats["unfilled_artifact_ref_count"] += 1
|
||||
continue
|
||||
path = str(ref.get("path", "")).strip()
|
||||
row = ready_rows.get((evidence_key, path))
|
||||
if row and row.get("sha256"):
|
||||
ref["sha256"] = row["sha256"]
|
||||
ref["contains_raw_content"] = False
|
||||
stats["prefilled_artifact_ref_count"] += 1
|
||||
else:
|
||||
stats["unfilled_artifact_ref_count"] += 1
|
||||
return stats
|
||||
|
||||
|
||||
def copy_template(
|
||||
skill_dir: Path,
|
||||
output_dir: Path,
|
||||
item: dict[str, Any],
|
||||
template_results: dict[str, dict[str, Any]],
|
||||
ready_rows: dict[tuple[str, str], dict[str, Any]],
|
||||
overwrite: bool,
|
||||
prefill_artifacts: bool,
|
||||
) -> dict[str, Any]:
|
||||
key = str(item.get("evidence_key", ""))
|
||||
template_result = template_results.get(key, {})
|
||||
@@ -83,6 +130,8 @@ def copy_template(
|
||||
"status": "skipped",
|
||||
"template_path": rel_path(template_path, skill_dir),
|
||||
"output_path": rel_path(output_path, skill_dir),
|
||||
"prefilled_artifact_ref_count": 0,
|
||||
"unfilled_artifact_ref_count": 0,
|
||||
"errors": errors,
|
||||
}
|
||||
|
||||
@@ -92,16 +141,36 @@ def copy_template(
|
||||
"status": "exists",
|
||||
"template_path": rel_path(template_path, skill_dir),
|
||||
"output_path": rel_path(output_path, skill_dir),
|
||||
"prefilled_artifact_ref_count": 0,
|
||||
"unfilled_artifact_ref_count": 0,
|
||||
"errors": [],
|
||||
}
|
||||
|
||||
payload = load_template_payload(template_path, errors)
|
||||
if errors or payload is None:
|
||||
return {
|
||||
"evidence_key": key,
|
||||
"status": "skipped",
|
||||
"template_path": rel_path(template_path, skill_dir),
|
||||
"output_path": rel_path(output_path, skill_dir),
|
||||
"prefilled_artifact_ref_count": 0,
|
||||
"unfilled_artifact_ref_count": 0,
|
||||
"errors": errors or ["template file is not a JSON object"],
|
||||
}
|
||||
|
||||
prefill_stats = (
|
||||
prefill_artifact_refs(payload, key, ready_rows)
|
||||
if prefill_artifacts
|
||||
else {"prefilled_artifact_ref_count": 0, "unfilled_artifact_ref_count": 0}
|
||||
)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(template_path, output_path)
|
||||
write_json(output_path, payload)
|
||||
return {
|
||||
"evidence_key": key,
|
||||
"status": "written",
|
||||
"template_path": rel_path(template_path, skill_dir),
|
||||
"output_path": rel_path(output_path, skill_dir),
|
||||
**prefill_stats,
|
||||
"errors": [],
|
||||
}
|
||||
|
||||
@@ -210,6 +279,7 @@ def render_readme(report: dict[str, Any]) -> str:
|
||||
"3. Set `template_only` to `false` only after real evidence exists.",
|
||||
"4. Set attestation booleans truthfully; do not include credentials, raw prompts, raw outputs, transcripts, notes, or private user content.",
|
||||
"5. Validate the packet before asking the ledger reviewer to accept it.",
|
||||
"6. Optional artifact prefill only inserts SHA-256 digests for current local aggregate artifacts; it does not mark a draft as real evidence.",
|
||||
"",
|
||||
"## Commands",
|
||||
"",
|
||||
@@ -219,11 +289,13 @@ def render_readme(report: dict[str, Any]) -> str:
|
||||
"",
|
||||
"## Drafts",
|
||||
"",
|
||||
"| Evidence | Draft | Status |",
|
||||
"| --- | --- | --- |",
|
||||
"| Evidence | Draft | Status | Prefilled refs |",
|
||||
"| --- | --- | --- | ---: |",
|
||||
]
|
||||
for item in report["files"]:
|
||||
lines.append(f"| `{item['evidence_key']}` | `{item['output_path']}` | `{item['status']}` |")
|
||||
lines.append(
|
||||
f"| `{item['evidence_key']}` | `{item['output_path']}` | `{item['status']}` | `{item.get('prefilled_artifact_ref_count', 0)}` |"
|
||||
)
|
||||
lines.extend(["", "## Execution Runbook", ""])
|
||||
for item in report.get("evidence_items", []):
|
||||
must_collect = item.get("must_collect", {}) if isinstance(item.get("must_collect", {}), dict) else {}
|
||||
@@ -304,6 +376,7 @@ def render_html_files(files: list[dict[str, Any]]) -> str:
|
||||
<dl>
|
||||
<dt>Template</dt><dd><code>{template}</code></dd>
|
||||
<dt>Draft</dt><dd><code>{output}</code></dd>
|
||||
<dt>Prefill</dt><dd>{prefill} artifact refs</dd>
|
||||
</dl>
|
||||
{errors}
|
||||
</article>
|
||||
@@ -312,6 +385,7 @@ def render_html_files(files: list[dict[str, Any]]) -> str:
|
||||
key=html_text(item.get("evidence_key", "")),
|
||||
template=html_text(item.get("template_path", "")),
|
||||
output=html_text(item.get("output_path", "")),
|
||||
prefill=html_text(item.get("prefilled_artifact_ref_count", 0)),
|
||||
errors=(
|
||||
"<ul class=\"errors\">"
|
||||
+ render_html_list(item.get("errors", []), "No errors.")
|
||||
@@ -428,6 +502,7 @@ def render_html(report: dict[str, Any]) -> str:
|
||||
("Existing", summary["existing_count"]),
|
||||
("Skipped", summary["skipped_count"]),
|
||||
("Artifacts", f"{artifact_ready}/{artifact_total}"),
|
||||
("Prefilled", summary.get("artifact_ref_prefill_count", 0)),
|
||||
]
|
||||
stat_html = "".join(f"<article><span>{html_text(label)}</span><strong>{html_text(value)}</strong></article>" for label, value in stats)
|
||||
evidence_html = "".join(render_html_item(item) for item in report.get("evidence_items", []))
|
||||
@@ -457,7 +532,7 @@ def render_html(report: dict[str, Any]) -> str:
|
||||
h3 {{ margin:4px 0 10px; font-size:22px; }}
|
||||
h4 {{ margin:0 0 8px; font-size:16px; }}
|
||||
.lede {{ max-width:800px; color:var(--muted); font-size:20px; }}
|
||||
.stats {{ display:grid; grid-template-columns:repeat(5, minmax(0,1fr)); gap:12px; margin:26px 0 0; }}
|
||||
.stats {{ display:grid; grid-template-columns:repeat(6, minmax(0,1fr)); gap:12px; margin:26px 0 0; }}
|
||||
.stats article, .panel, .draft-card, .evidence-card {{ border:1px solid var(--line); border-radius:8px; background:#fff; }}
|
||||
.stats article {{ padding:16px; }}
|
||||
.stats span, .draft-card span, .evidence-card span, .muted {{ color:var(--muted); }}
|
||||
@@ -495,11 +570,11 @@ def render_html(report: dict[str, Any]) -> str:
|
||||
<section class="hero">
|
||||
<span class="eyebrow">Evidence Intake</span>
|
||||
<h1>World-Class Evidence Submission Kit</h1>
|
||||
<p class="lede">Use this cockpit to prepare human and external evidence packets. Drafts are not accepted evidence, and this page never changes the ledger result.</p>
|
||||
<p class="lede">Use this cockpit to prepare human and external evidence packets. Drafts are not accepted evidence, artifact prefill only inserts local SHA-256 digests, and this page never changes the ledger result.</p>
|
||||
<div class="stats">{stat_html}</div>
|
||||
</section>
|
||||
<section class="section two-col" id="workflow">
|
||||
<article class="panel"><h2>Workflow</h2><ol><li>Run the real provider, human review, native permission, or native client telemetry work first.</li><li>Edit the matching JSON draft with aggregate artifact references and provenance metadata.</li><li>Set template_only to false only after real evidence exists.</li><li>Validate intake, refresh the ledger, then guard public claims.</li></ol></article>
|
||||
<article class="panel"><h2>Workflow</h2><ol><li>Run the real provider, human review, native permission, or native client telemetry work first.</li><li>Edit the matching JSON draft with aggregate artifact references and provenance metadata.</li><li>Set template_only to false only after real evidence exists.</li><li>Use prefilled SHA-256 values as convenience data, not evidence acceptance.</li><li>Validate intake, refresh the ledger, then guard public claims.</li></ol></article>
|
||||
<aside class="panel"><h2>Commands</h2><ul class="commands">{render_html_commands(report['commands'])}</ul></aside>
|
||||
</section>
|
||||
<section class="section" id="drafts"><h2>Drafts</h2><div class="draft-grid">{render_html_files(report['files'])}</div></section>
|
||||
@@ -519,6 +594,7 @@ def build_submission_kit(
|
||||
generated_at: str,
|
||||
evidence_keys: list[str] | None = None,
|
||||
overwrite: bool = False,
|
||||
prefill_artifacts: bool = False,
|
||||
output_html: Path | None = None,
|
||||
) -> dict[str, Any]:
|
||||
intake = build_intake(skill_dir, generated_at, submissions_dir=output_dir)
|
||||
@@ -526,8 +602,20 @@ def build_submission_kit(
|
||||
valid_keys = {str(item.get("evidence_key")) for item in intake.get("operator_checklist", [])}
|
||||
unknown_keys = sorted(set(evidence_keys or []) - valid_keys)
|
||||
template_results = template_result_by_key(intake)
|
||||
files = [copy_template(skill_dir, output_dir, item, template_results, overwrite) for item in items]
|
||||
artifact_checklist = build_artifact_checklist(skill_dir, items)
|
||||
ready_rows = artifact_rows_by_key_and_path(artifact_checklist)
|
||||
files = [
|
||||
copy_template(
|
||||
skill_dir,
|
||||
output_dir,
|
||||
item,
|
||||
template_results,
|
||||
ready_rows,
|
||||
overwrite,
|
||||
prefill_artifacts,
|
||||
)
|
||||
for item in items
|
||||
]
|
||||
source_checklist = build_source_checklist(items)
|
||||
manifest_path = output_dir / "submission_manifest.json"
|
||||
readme_path = output_dir / "README.md"
|
||||
@@ -535,6 +623,8 @@ def build_submission_kit(
|
||||
written_count = sum(1 for item in files if item["status"] == "written")
|
||||
existing_count = sum(1 for item in files if item["status"] == "exists")
|
||||
skipped_count = sum(1 for item in files if item["status"] == "skipped")
|
||||
prefilled_artifact_ref_count = sum(item.get("prefilled_artifact_ref_count", 0) for item in files)
|
||||
unfilled_artifact_ref_count = sum(item.get("unfilled_artifact_ref_count", 0) for item in files)
|
||||
artifact_ready_count = sum(1 for item in artifact_checklist if item.get("artifact_ref_ready"))
|
||||
artifact_missing_count = sum(1 for item in artifact_checklist if not item.get("artifact_ref_ready"))
|
||||
artifact_glob_count = sum(1 for item in artifact_checklist if item.get("concrete_reference_required"))
|
||||
@@ -557,6 +647,9 @@ def build_submission_kit(
|
||||
"artifact_ready_count": artifact_ready_count,
|
||||
"artifact_missing_count": artifact_missing_count,
|
||||
"artifact_glob_expansion_count": artifact_glob_count,
|
||||
"artifact_prefill_enabled": prefill_artifacts,
|
||||
"artifact_ref_prefill_count": prefilled_artifact_ref_count,
|
||||
"artifact_ref_unfilled_count": unfilled_artifact_ref_count,
|
||||
**source_summary,
|
||||
"drafts_count_as_evidence": False,
|
||||
"ledger_counts_submission_as_completion": False,
|
||||
@@ -574,6 +667,7 @@ def build_submission_kit(
|
||||
},
|
||||
"safety": {
|
||||
"template_only_drafts": True,
|
||||
"artifact_prefill_counts_as_evidence": False,
|
||||
"real_evidence_required_before_template_only_false": True,
|
||||
"raw_content_allowed": False,
|
||||
"credentials_allowed": False,
|
||||
@@ -599,6 +693,11 @@ def main() -> None:
|
||||
parser.add_argument("--output-dir", default="evidence/world_class/submission-kit")
|
||||
parser.add_argument("--evidence-key", action="append", default=[])
|
||||
parser.add_argument("--overwrite", action="store_true")
|
||||
parser.add_argument(
|
||||
"--prefill-artifacts",
|
||||
action="store_true",
|
||||
help="Insert SHA-256 digests for currently available aggregate artifacts while keeping drafts template-only.",
|
||||
)
|
||||
parser.add_argument("--generated-at", default=date.today().isoformat())
|
||||
parser.add_argument("--output-html")
|
||||
args = parser.parse_args()
|
||||
@@ -613,6 +712,7 @@ def main() -> None:
|
||||
args.generated_at,
|
||||
evidence_keys=args.evidence_key,
|
||||
overwrite=args.overwrite,
|
||||
prefill_artifacts=args.prefill_artifacts,
|
||||
output_html=Path(args.output_html).resolve() if args.output_html else None,
|
||||
)
|
||||
print(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
|
||||
@@ -237,6 +237,11 @@ def build_parser(command_handlers: dict[str, Callable[[argparse.Namespace], int]
|
||||
world_class_submission_kit_cmd.add_argument("--output-dir")
|
||||
world_class_submission_kit_cmd.add_argument("--evidence-key", action="append", default=[])
|
||||
world_class_submission_kit_cmd.add_argument("--overwrite", action="store_true")
|
||||
world_class_submission_kit_cmd.add_argument(
|
||||
"--prefill-artifacts",
|
||||
action="store_true",
|
||||
help="Insert SHA-256 digests for currently available aggregate artifacts while keeping drafts template-only.",
|
||||
)
|
||||
world_class_submission_kit_cmd.add_argument("--generated-at")
|
||||
world_class_submission_kit_cmd.add_argument("--output-html")
|
||||
world_class_submission_kit_cmd.set_defaults(func=_handler(command_handlers, "command_world_class_submission_kit"))
|
||||
|
||||
@@ -196,6 +196,8 @@ def command_world_class_submission_kit(args: argparse.Namespace) -> int:
|
||||
cmd.extend(["--evidence-key", key])
|
||||
if args.overwrite:
|
||||
cmd.append("--overwrite")
|
||||
if args.prefill_artifacts:
|
||||
cmd.append("--prefill-artifacts")
|
||||
if args.generated_at:
|
||||
cmd.extend(["--generated-at", args.generated_at])
|
||||
if args.output_html:
|
||||
|
||||
@@ -499,6 +499,7 @@ def assert_documented_submission_commands() -> None:
|
||||
'SUBMISSIONS_DIR="${SUBMISSIONS_DIR:-evidence/world_class/submissions}"',
|
||||
'world-class-preflight . --submissions-dir "$SUBMISSIONS_DIR"',
|
||||
'world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR"',
|
||||
'world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR" --prefill-artifacts',
|
||||
'world-class-intake . --submissions-dir "$SUBMISSIONS_DIR"',
|
||||
'world-class-submission-review . --submissions-dir "$SUBMISSIONS_DIR"',
|
||||
'world-class-ledger . --submissions-dir "$SUBMISSIONS_DIR"',
|
||||
@@ -614,8 +615,11 @@ def main() -> None:
|
||||
kit_draft = json.loads((kit_dir / "provider-holdout.json").read_text(encoding="utf-8"))
|
||||
assert kit_draft["template_only"] is True, kit_draft
|
||||
assert kit_draft["attestation"]["real_external_or_human_evidence"] is False, kit_draft
|
||||
assert "sha256" not in kit_draft["artifact_refs"][0], kit_draft
|
||||
kit_manifest = json.loads((kit_dir / "submission_manifest.json").read_text(encoding="utf-8"))
|
||||
assert kit_manifest["summary"]["ledger_counts_submission_as_completion"] is False, kit_manifest["summary"]
|
||||
assert kit_manifest["summary"]["artifact_prefill_enabled"] is False, kit_manifest["summary"]
|
||||
assert kit_manifest["summary"]["artifact_ref_prefill_count"] == 0, kit_manifest["summary"]
|
||||
assert kit_manifest["artifact_checklist"] == kit_payload["artifact_checklist"], kit_manifest["artifact_checklist"]
|
||||
assert kit_manifest["source_checklist"] == kit_payload["source_checklist"], kit_manifest["source_checklist"]
|
||||
assert kit_manifest["artifacts"]["html"].endswith("tests/tmp_world_class_evidence_intake/submission_kit/index.html"), kit_manifest["artifacts"]
|
||||
@@ -642,6 +646,33 @@ def main() -> None:
|
||||
assert "output-exec --provider-runner openai" in kit_html, kit_html
|
||||
assert "Do not include credentials, raw prompts, raw outputs, transcripts, notes, or private user content." in kit_html, kit_html
|
||||
|
||||
prefilled_kit_dir = TMP / "prefilled_submission_kit"
|
||||
prefilled_proc = run_kit(
|
||||
"--output-dir",
|
||||
str(prefilled_kit_dir),
|
||||
"--evidence-key",
|
||||
"provider-holdout",
|
||||
"--prefill-artifacts",
|
||||
)
|
||||
prefilled_payload = json.loads(prefilled_proc.stdout)
|
||||
assert prefilled_payload["summary"]["artifact_prefill_enabled"] is True, prefilled_payload["summary"]
|
||||
assert prefilled_payload["summary"]["artifact_ref_prefill_count"] == 1, prefilled_payload["summary"]
|
||||
assert prefilled_payload["summary"]["artifact_ref_unfilled_count"] == 0, prefilled_payload["summary"]
|
||||
assert prefilled_payload["summary"]["drafts_count_as_evidence"] is False, prefilled_payload["summary"]
|
||||
assert prefilled_payload["safety"]["artifact_prefill_counts_as_evidence"] is False, prefilled_payload["safety"]
|
||||
assert prefilled_payload["files"][0]["prefilled_artifact_ref_count"] == 1, prefilled_payload["files"]
|
||||
prefilled_draft = json.loads((prefilled_kit_dir / "provider-holdout.json").read_text(encoding="utf-8"))
|
||||
assert prefilled_draft["template_only"] is True, prefilled_draft
|
||||
assert prefilled_draft["attestation"]["real_external_or_human_evidence"] is False, prefilled_draft
|
||||
assert len(prefilled_draft["artifact_refs"][0]["sha256"]) == 64, prefilled_draft
|
||||
assert prefilled_draft["artifact_refs"][0]["contains_raw_content"] is False, prefilled_draft
|
||||
prefilled_readme = (prefilled_kit_dir / "README.md").read_text(encoding="utf-8")
|
||||
assert "Optional artifact prefill only inserts SHA-256 digests" in prefilled_readme, prefilled_readme
|
||||
assert "does not mark a draft as real evidence" in prefilled_readme, prefilled_readme
|
||||
prefilled_html = (prefilled_kit_dir / "index.html").read_text(encoding="utf-8")
|
||||
assert "artifact prefill only inserts local SHA-256 digests" in prefilled_html, prefilled_html
|
||||
assert "<dt>Prefill</dt><dd>1 artifact refs</dd>" in prefilled_html, prefilled_html
|
||||
|
||||
native_kit_dir = TMP / "native_permission_kit"
|
||||
native_kit_proc = run_kit("--output-dir", str(native_kit_dir), "--evidence-key", "native-permission-enforcement")
|
||||
native_kit_payload = json.loads(native_kit_proc.stdout)
|
||||
|
||||
Reference in New Issue
Block a user