@riddledc/riddle-proof 0.8.32 → 0.8.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced/index.d.cts +1 -1
- package/dist/advanced/index.d.ts +1 -1
- package/dist/advanced/proof-run-engine.d.cts +1 -1
- package/dist/advanced/proof-run-engine.d.ts +1 -1
- package/dist/{proof-run-engine-DeHxtGnW.d.cts → proof-run-engine-4dM37pEx.d.cts} +3 -3
- package/dist/{proof-run-engine-DYfmd8d7.d.ts → proof-run-engine-BqaeqAze.d.ts} +3 -3
- package/dist/proof-run-engine.d.cts +1 -1
- package/dist/proof-run-engine.d.ts +1 -1
- package/package.json +1 -1
- package/runtime/lib/ship.py +136 -6
- package/runtime/tests/ship_artifact_publication.py +16 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { b as runner } from '../runner-4LJ5z0D-.cjs';
|
|
2
2
|
export { l as engineHarness } from '../engine-harness-LBfqbFSe.cjs';
|
|
3
3
|
export { p as proofRunCore } from '../proof-run-core-B1GeqkR8.cjs';
|
|
4
|
-
export { p as proofRunEngine } from '../proof-run-engine-
|
|
4
|
+
export { p as proofRunEngine } from '../proof-run-engine-4dM37pEx.cjs';
|
|
5
5
|
import '../types.cjs';
|
package/dist/advanced/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { b as runner } from '../runner-BdQpOkZD.js';
|
|
2
2
|
export { l as engineHarness } from '../engine-harness-CMACHP6A.js';
|
|
3
3
|
export { p as proofRunCore } from '../proof-run-core-B1GeqkR8.js';
|
|
4
|
-
export { p as proofRunEngine } from '../proof-run-engine-
|
|
4
|
+
export { p as proofRunEngine } from '../proof-run-engine-BqaeqAze.js';
|
|
5
5
|
import '../types.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-
|
|
1
|
+
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-4dM37pEx.cjs';
|
|
2
2
|
import '../proof-run-core-B1GeqkR8.cjs';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-
|
|
1
|
+
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-BqaeqAze.js';
|
|
2
2
|
import '../proof-run-core-B1GeqkR8.js';
|
|
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
292
292
|
blocking?: boolean;
|
|
293
293
|
details?: Record<string, unknown>;
|
|
294
294
|
ok: boolean;
|
|
295
|
-
action: "
|
|
295
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
296
296
|
state_path: string;
|
|
297
297
|
stage: any;
|
|
298
298
|
summary: string;
|
|
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
382
382
|
continueWithStage?: WorkflowStage | null;
|
|
383
383
|
blocking?: boolean;
|
|
384
384
|
details?: Record<string, unknown>;
|
|
385
|
-
action: "
|
|
385
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
386
386
|
state_path: string;
|
|
387
387
|
stage: any;
|
|
388
388
|
checkpoint: string;
|
|
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
659
659
|
error?: undefined;
|
|
660
660
|
} | {
|
|
661
661
|
ok: boolean;
|
|
662
|
-
action: "
|
|
662
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup";
|
|
663
663
|
state_path: string;
|
|
664
664
|
stage: any;
|
|
665
665
|
summary: string;
|
|
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
292
292
|
blocking?: boolean;
|
|
293
293
|
details?: Record<string, unknown>;
|
|
294
294
|
ok: boolean;
|
|
295
|
-
action: "
|
|
295
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
296
296
|
state_path: string;
|
|
297
297
|
stage: any;
|
|
298
298
|
summary: string;
|
|
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
382
382
|
continueWithStage?: WorkflowStage | null;
|
|
383
383
|
blocking?: boolean;
|
|
384
384
|
details?: Record<string, unknown>;
|
|
385
|
-
action: "
|
|
385
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
386
386
|
state_path: string;
|
|
387
387
|
stage: any;
|
|
388
388
|
checkpoint: string;
|
|
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
659
659
|
error?: undefined;
|
|
660
660
|
} | {
|
|
661
661
|
ok: boolean;
|
|
662
|
-
action: "
|
|
662
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup";
|
|
663
663
|
state_path: string;
|
|
664
664
|
stage: any;
|
|
665
665
|
summary: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import './proof-run-core-B1GeqkR8.cjs';
|
|
2
|
-
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-
|
|
2
|
+
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-4dM37pEx.cjs';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import './proof-run-core-B1GeqkR8.js';
|
|
2
|
-
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-
|
|
2
|
+
export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-BqaeqAze.js';
|
package/package.json
CHANGED
package/runtime/lib/ship.py
CHANGED
|
@@ -320,7 +320,20 @@ def local_artifact_sources_fingerprint(local_sources):
|
|
|
320
320
|
def public_proof_artifacts(state):
|
|
321
321
|
published = state.get('proof_artifact_publication') or {}
|
|
322
322
|
artifacts = published.get('artifacts') if isinstance(published, dict) else []
|
|
323
|
-
|
|
323
|
+
attachments = state.get('proof_image_attachments') or {}
|
|
324
|
+
attachment_artifacts = attachments.get('artifacts') if isinstance(attachments, dict) else []
|
|
325
|
+
public = [
|
|
326
|
+
{
|
|
327
|
+
**artifact,
|
|
328
|
+
'raw_url': artifact.get('attachment_url'),
|
|
329
|
+
'html_url': artifact.get('attachment_url'),
|
|
330
|
+
'embeddable': True,
|
|
331
|
+
'attachment': True,
|
|
332
|
+
}
|
|
333
|
+
for artifact in attachment_artifacts or []
|
|
334
|
+
if isinstance(artifact, dict) and artifact.get('attachment_url')
|
|
335
|
+
]
|
|
336
|
+
public.extend([artifact for artifact in artifacts or [] if isinstance(artifact, dict) and (artifact.get('raw_url') or artifact.get('html_url'))])
|
|
324
337
|
for artifact in collect_proof_artifact_sources(state):
|
|
325
338
|
url = str(artifact.get('url') or '').strip()
|
|
326
339
|
if is_http_url(url):
|
|
@@ -328,6 +341,7 @@ def public_proof_artifacts(state):
|
|
|
328
341
|
**artifact,
|
|
329
342
|
'raw_url': url,
|
|
330
343
|
'html_url': url,
|
|
344
|
+
'embeddable': True,
|
|
331
345
|
'published': False,
|
|
332
346
|
})
|
|
333
347
|
deduped = []
|
|
@@ -346,6 +360,8 @@ def first_public_artifact_url(state, role, kind=None):
|
|
|
346
360
|
continue
|
|
347
361
|
if kind and artifact.get('kind') != kind:
|
|
348
362
|
continue
|
|
363
|
+
if artifact.get('kind') == 'image' and artifact.get('embeddable') is False:
|
|
364
|
+
continue
|
|
349
365
|
return artifact.get('raw_url') or artifact.get('html_url') or artifact.get('url') or ''
|
|
350
366
|
return ''
|
|
351
367
|
|
|
@@ -362,6 +378,92 @@ def resolve_github_repo_name(repo_dir):
|
|
|
362
378
|
return ''
|
|
363
379
|
|
|
364
380
|
|
|
381
|
+
def resolve_github_repo_private(repo_dir):
|
|
382
|
+
result = sp.run(['gh', 'repo', 'view', '--json', 'isPrivate', '--jq', '.isPrivate'],
|
|
383
|
+
cwd=repo_dir, capture_output=True, text=True, timeout=30)
|
|
384
|
+
if result.returncode == 0:
|
|
385
|
+
text = result.stdout.strip().lower()
|
|
386
|
+
if text in ('true', 'false'):
|
|
387
|
+
return text == 'true'
|
|
388
|
+
return None
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def github_file_url(repo_name, ref, path_value, mode='blob'):
|
|
392
|
+
safe_path = urllib.parse.quote(str(path_value or '').lstrip('/'), safe='/._-')
|
|
393
|
+
return 'https://github.com/' + repo_name + '/' + mode + '/' + ref + '/' + safe_path
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def parse_github_image_markdown(line):
|
|
397
|
+
match = re.search(r'!\[[^\]]*\]\((https://github\.com/user-attachments/assets/[^)\s]+)\)', str(line or '').strip())
|
|
398
|
+
return match.group(1) if match else ''
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def upload_local_images_to_github_attachments(state, repo_dir):
|
|
402
|
+
if truthy(os.environ.get('RIDDLE_PROOF_DISABLE_GITHUB_IMAGE_ATTACHMENTS')):
|
|
403
|
+
state['proof_image_attachments'] = {'ok': False, 'skipped': True, 'reason': 'disabled'}
|
|
404
|
+
save_state(state)
|
|
405
|
+
return state['proof_image_attachments']
|
|
406
|
+
|
|
407
|
+
image_sources = [
|
|
408
|
+
artifact for artifact in local_proof_artifact_sources(state)
|
|
409
|
+
if artifact.get('kind') == 'image' and artifact.get('path')
|
|
410
|
+
]
|
|
411
|
+
if not image_sources:
|
|
412
|
+
state['proof_image_attachments'] = {'ok': True, 'skipped': True, 'reason': 'no local image artifacts'}
|
|
413
|
+
save_state(state)
|
|
414
|
+
return state['proof_image_attachments']
|
|
415
|
+
|
|
416
|
+
repo_name = resolve_github_repo_name(repo_dir)
|
|
417
|
+
if not repo_name:
|
|
418
|
+
state['proof_image_attachments'] = {'ok': False, 'skipped': True, 'reason': 'repo name unavailable'}
|
|
419
|
+
save_state(state)
|
|
420
|
+
return state['proof_image_attachments']
|
|
421
|
+
|
|
422
|
+
timeout_seconds = int(os.environ.get('RIDDLE_PROOF_GH_IMAGE_TIMEOUT_SECONDS') or '15')
|
|
423
|
+
command = ['gh', 'image'] + [artifact.get('path') for artifact in image_sources] + ['--repo', repo_name]
|
|
424
|
+
try:
|
|
425
|
+
result = sp.run(command, cwd=repo_dir, capture_output=True, text=True, timeout=timeout_seconds)
|
|
426
|
+
except sp.TimeoutExpired:
|
|
427
|
+
state['proof_image_attachments'] = {'ok': False, 'skipped': True, 'reason': 'gh image timed out'}
|
|
428
|
+
save_state(state)
|
|
429
|
+
return state['proof_image_attachments']
|
|
430
|
+
|
|
431
|
+
if result.returncode != 0:
|
|
432
|
+
state['proof_image_attachments'] = {
|
|
433
|
+
'ok': False,
|
|
434
|
+
'skipped': True,
|
|
435
|
+
'reason': 'gh image failed',
|
|
436
|
+
'stderr': (result.stderr or result.stdout or '')[:500],
|
|
437
|
+
}
|
|
438
|
+
save_state(state)
|
|
439
|
+
return state['proof_image_attachments']
|
|
440
|
+
|
|
441
|
+
urls = [parse_github_image_markdown(line) for line in result.stdout.splitlines()]
|
|
442
|
+
urls = [url for url in urls if url]
|
|
443
|
+
if not urls:
|
|
444
|
+
state['proof_image_attachments'] = {'ok': False, 'skipped': True, 'reason': 'gh image returned no attachment URLs'}
|
|
445
|
+
save_state(state)
|
|
446
|
+
return state['proof_image_attachments']
|
|
447
|
+
|
|
448
|
+
artifacts = []
|
|
449
|
+
for index, artifact in enumerate(image_sources):
|
|
450
|
+
if index >= len(urls):
|
|
451
|
+
break
|
|
452
|
+
artifacts.append({
|
|
453
|
+
**artifact,
|
|
454
|
+
'attachment_url': urls[index],
|
|
455
|
+
'attachment': True,
|
|
456
|
+
'embeddable': True,
|
|
457
|
+
})
|
|
458
|
+
state['proof_image_attachments'] = {
|
|
459
|
+
'ok': True,
|
|
460
|
+
'repo': repo_name,
|
|
461
|
+
'artifacts': artifacts,
|
|
462
|
+
}
|
|
463
|
+
save_state(state)
|
|
464
|
+
return state['proof_image_attachments']
|
|
465
|
+
|
|
466
|
+
|
|
365
467
|
def write_artifact_readme(path_value, state, artifacts):
|
|
366
468
|
lines = [
|
|
367
469
|
'# Riddle Proof Artifacts',
|
|
@@ -403,6 +505,7 @@ def publish_local_proof_artifacts_to_github(state, repo_dir, pr_num):
|
|
|
403
505
|
repo_name = resolve_github_repo_name(repo_dir)
|
|
404
506
|
if not repo_name:
|
|
405
507
|
raise SystemExit('Could not resolve GitHub repository name for proof artifact publication.')
|
|
508
|
+
repo_private = resolve_github_repo_private(repo_dir)
|
|
406
509
|
|
|
407
510
|
run_id = safe_slug(state.get('run_id') or str(int(time.time())), 'run')
|
|
408
511
|
pr_slug = safe_slug('pr-' + str(pr_num or 'unknown'), 'pr')
|
|
@@ -467,16 +570,18 @@ def publish_local_proof_artifacts_to_github(state, repo_dir, pr_num):
|
|
|
467
570
|
for artifact in published:
|
|
468
571
|
if artifact.get('published'):
|
|
469
572
|
published_path = artifact.get('published_path')
|
|
470
|
-
artifact['raw_url'] =
|
|
471
|
-
artifact['html_url'] =
|
|
573
|
+
artifact['raw_url'] = github_file_url(repo_name, commit, published_path, 'raw')
|
|
574
|
+
artifact['html_url'] = github_file_url(repo_name, commit, published_path, 'blob')
|
|
575
|
+
artifact['embeddable'] = False if repo_private is True and artifact.get('kind') == 'image' else True
|
|
472
576
|
publication = {
|
|
473
577
|
'ok': True,
|
|
474
578
|
'branch': artifact_branch,
|
|
475
579
|
'commit': commit,
|
|
476
580
|
'repo': repo_name,
|
|
477
|
-
'
|
|
478
|
-
'
|
|
479
|
-
'
|
|
581
|
+
'repo_private': repo_private,
|
|
582
|
+
'html_url': github_file_url(repo_name, commit, artifact_dir_name, 'tree'),
|
|
583
|
+
'manifest_url': github_file_url(repo_name, commit, artifact_dir_name + '/proof-artifacts.json', 'blob'),
|
|
584
|
+
'readme_url': github_file_url(repo_name, commit, artifact_dir_name + '/README.md', 'blob'),
|
|
480
585
|
'source_fingerprint': source_fingerprint,
|
|
481
586
|
'artifacts': published,
|
|
482
587
|
}
|
|
@@ -1075,6 +1180,12 @@ if publication.get('ok') and not publication.get('skipped'):
|
|
|
1075
1180
|
elif publication.get('skipped'):
|
|
1076
1181
|
print('Proof artifact publication skipped: ' + publication.get('reason', 'unknown'))
|
|
1077
1182
|
|
|
1183
|
+
image_attachments = upload_local_images_to_github_attachments(s, repo_dir)
|
|
1184
|
+
if image_attachments.get('ok') and not image_attachments.get('skipped'):
|
|
1185
|
+
print('Proof images attached: ' + str(len(image_attachments.get('artifacts') or [])))
|
|
1186
|
+
elif image_attachments.get('skipped'):
|
|
1187
|
+
print('Proof image attachment skipped: ' + image_attachments.get('reason', 'unknown'))
|
|
1188
|
+
|
|
1078
1189
|
# Post proof comment on PR
|
|
1079
1190
|
body = '## Riddle Proof — Proof of Fix\n\n'
|
|
1080
1191
|
body += '**Goal:** ' + s.get('change_request', '') + '\n\n'
|
|
@@ -1094,15 +1205,34 @@ if publication.get('ok') and not publication.get('skipped'):
|
|
|
1094
1205
|
before_image = first_public_artifact_url(s, 'before', 'image')
|
|
1095
1206
|
prod_image = first_public_artifact_url(s, 'prod', 'image')
|
|
1096
1207
|
after_image = first_public_artifact_url(s, 'after', 'image')
|
|
1208
|
+
linked_image_artifacts = [
|
|
1209
|
+
artifact for artifact in public_artifacts
|
|
1210
|
+
if artifact.get('kind') == 'image'
|
|
1211
|
+
and artifact.get('embeddable') is False
|
|
1212
|
+
and (artifact.get('html_url') or artifact.get('raw_url'))
|
|
1213
|
+
]
|
|
1097
1214
|
if before_image:
|
|
1098
1215
|
body += '### Before\n\n\n'
|
|
1099
1216
|
if prod_image:
|
|
1100
1217
|
body += '### Prod\n\n\n'
|
|
1101
1218
|
if after_image:
|
|
1102
1219
|
body += '### After\n\n\n'
|
|
1220
|
+
elif linked_image_artifacts:
|
|
1221
|
+
body += '### After evidence\nA screenshot artifact was captured, but GitHub attachment upload was unavailable; linked image artifacts are listed below.\n\n'
|
|
1103
1222
|
else:
|
|
1104
1223
|
body += '### After evidence\nNo after screenshot was captured for this verification mode; structured evidence is summarized below.\n\n'
|
|
1105
1224
|
|
|
1225
|
+
if linked_image_artifacts:
|
|
1226
|
+
body += '### Image artifacts\n'
|
|
1227
|
+
for artifact in linked_image_artifacts[:12]:
|
|
1228
|
+
label = artifact.get('name') or artifact.get('filename') or 'image'
|
|
1229
|
+
url = artifact.get('html_url') or artifact.get('raw_url')
|
|
1230
|
+
body += '- [' + str(label) + '](' + str(url) + ')'
|
|
1231
|
+
if artifact.get('role'):
|
|
1232
|
+
body += ' (' + str(artifact.get('role')) + ')'
|
|
1233
|
+
body += '\n'
|
|
1234
|
+
body += '\n'
|
|
1235
|
+
|
|
1106
1236
|
data_artifacts = [
|
|
1107
1237
|
artifact for artifact in public_artifacts
|
|
1108
1238
|
if artifact.get('kind') != 'image' and (artifact.get('html_url') or artifact.get('raw_url'))
|
|
@@ -27,7 +27,15 @@ import sys
|
|
|
27
27
|
|
|
28
28
|
args = sys.argv[1:]
|
|
29
29
|
if args[:3] == ["repo", "view", "--json"]:
|
|
30
|
-
|
|
30
|
+
if "isPrivate" in args:
|
|
31
|
+
print("true")
|
|
32
|
+
else:
|
|
33
|
+
print("example/test-repo")
|
|
34
|
+
raise SystemExit(0)
|
|
35
|
+
if args and args[0] == "image":
|
|
36
|
+
image_paths = [arg for arg in args[1:] if not arg.startswith("--") and arg != "example/test-repo"]
|
|
37
|
+
for index, image_path in enumerate(image_paths):
|
|
38
|
+
print(f"")
|
|
31
39
|
raise SystemExit(0)
|
|
32
40
|
if args[:2] == ["pr", "list"]:
|
|
33
41
|
print("")
|
|
@@ -163,13 +171,16 @@ def main():
|
|
|
163
171
|
assert publication.get("ok") is True, "proof artifact publication should be recorded"
|
|
164
172
|
assert publication.get("artifacts"), "published artifact list should be recorded"
|
|
165
173
|
assert updated.get("ship_report", {}).get("after_artifact_url", "").startswith(
|
|
166
|
-
"https://
|
|
167
|
-
), "ship report should expose a
|
|
174
|
+
"https://github.com/user-attachments/assets/"
|
|
175
|
+
), "ship report should expose a GitHub-hosted attachment URL for the after artifact"
|
|
168
176
|
|
|
169
177
|
comment = comment_body_path.read_text(encoding="utf-8")
|
|
170
178
|
assert "file://" not in comment, "PR proof comment must not expose local file URLs"
|
|
171
|
-
assert "
|
|
172
|
-
"PR proof comment
|
|
179
|
+
assert "raw.githubusercontent.com" not in comment, (
|
|
180
|
+
"PR proof comment must not depend on unauthenticated raw GitHub URLs"
|
|
181
|
+
)
|
|
182
|
+
assert "
|
|
174
185
|
assert "[proof.json](https://github.com/example/test-repo/blob/" in comment, (
|
|
175
186
|
"PR proof comment should link the structured proof JSON"
|