Skip to content
Merged
120 changes: 112 additions & 8 deletions .github/workflows/igraph-live-proof.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ jobs:
run: |
for attempt in $(seq 1 36); do
status="$(curl -sS --max-time 120 -o /tmp/discover.json -w '%{http_code}' "$IGRAPH_URL/v1/discover?query=%2A" || true)"
echo "Discovery attempt $attempt returned HTTP $status"
echo "Wildcard discovery attempt $attempt returned HTTP $status"
if [ "$status" = "200" ] && jq -e '
.live == true and
((.candidates | length) > 0) and
Expand All @@ -155,7 +155,7 @@ jobs:
break
fi
if [ "$attempt" = "36" ]; then
echo "Live discovery did not return a dataset with loaded lineage"
echo "Live wildcard discovery did not return a dataset with loaded lineage"
cat /tmp/discover.json || true
exit 1
fi
Expand All @@ -167,11 +167,33 @@ jobs:
(.candidates | length) > 0 and
(any(.candidates[]; (.downstream_count // 0) > 0))
' /tmp/discover.json
URN="$(jq -r '.candidates | max_by(.downstream_count) | .urn' /tmp/discover.json)"
test -n "$URN"
test "$URN" != "null"
echo "Selected live dataset: $URN"
jq -n --arg entity "$URN" '{action:"modify_asset", entity:$entity}' >/tmp/analyze-request.json

TARGET_URN="urn:li:dataset:(urn:li:dataPlatform:snowflake,b2fd91.order_entry_db.order_entry.order_items,PROD)"
for attempt in $(seq 1 36); do
status="$(curl -sS --get --max-time 120 \
-o /tmp/target-discover.json -w '%{http_code}' \
"$IGRAPH_URL/v1/discover" --data-urlencode "query=order_items" || true)"
echo "Target discovery attempt $attempt returned HTTP $status"
if [ "$status" = "200" ] && jq -e --arg target "$TARGET_URN" '
.live == true and
any(.candidates[]; .urn == $target and (.downstream_count // 0) > 0)
' /tmp/target-discover.json >/dev/null 2>&1; then
break
fi
if [ "$attempt" = "36" ]; then
echo "Target order_items dataset did not become discoverable with loaded lineage"
cat /tmp/target-discover.json || true
exit 1
fi
sleep 5
done
cat /tmp/target-discover.json
jq -e --arg target "$TARGET_URN" '
.live == true and
any(.candidates[]; .urn == $target and (.downstream_count // 0) > 0)
' /tmp/target-discover.json
echo "Selected deterministic live dataset: $TARGET_URN"
jq -n --arg entity "$TARGET_URN" '{action:"modify_asset", entity:$entity}' >/tmp/analyze-request.json

- name: Prove Pact compilation and verification
run: |
Expand All @@ -191,6 +213,88 @@ jobs:
--data-binary @/tmp/pact.json | tee /tmp/verify.json
jq -e '.verified == true and (all(.validations[]; .status == "pass"))' /tmp/verify.json

- name: Prove authorized staging execution and replay protection
run: |
refresh_pact() {
curl -fsS --max-time 300 -X POST "$IGRAPH_URL/v1/analyze" \
-H 'content-type: application/json' \
--data-binary @/tmp/analyze-request.json | tee /tmp/analyze.json
jq -e '
(.pact.context.live == true) and
(.pact.context.retrieval_complete == true) and
((.pact.context.downstream | length) > 0) and
((.pact.signature | length) >= 32) and
((.pact.context_hash | length) > 0)
' /tmp/analyze.json
jq '.pact' /tmp/analyze.json >/tmp/pact.json
curl -fsS --max-time 300 -X POST "$IGRAPH_URL/v1/verify" \
-H 'content-type: application/json' \
--data-binary @/tmp/pact.json | tee /tmp/verify.json
jq -e '.verified == true and (all(.validations[]; .status == "pass"))' /tmp/verify.json
}

for attempt in $(seq 1 5); do
echo "Authorized staging attempt $attempt"
ARTIFACT_SHA="$(jq -r '.execution_scope.deploy_staging.artifact_hashes[0]' /tmp/pact.json)"
test -n "$ARTIFACT_SHA"
test "$ARTIFACT_SHA" != "null"
jq -n --slurpfile pact /tmp/pact.json --arg artifact "$ARTIFACT_SHA" \
'{pact:$pact[0], action:"deploy_staging", parameters:{target:"staging", artifact_sha256:$artifact}, human_approved:true}' \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Back the approval claim with a human-controlled gate

On automatic pull_request and push runs, the workflow unconditionally sets human_approved:true; there is no protected environment, reviewer gate, or approval-derived input anywhere in this workflow. The run therefore proves only that a caller-controlled Boolean unlocks the approval branch, not the documented claim that an explicitly human-approved action executed. Source this value from a human-controlled gate or qualify the proof as simulated approval.

Useful? React with 👍 / 👎.

>/tmp/execute-request.json

status="$(curl -sS --max-time 120 -o /tmp/execute-response.json -w '%{http_code}' \
-X POST "$IGRAPH_URL/v1/actions/execute" \
-H 'content-type: application/json' \
--data-binary @/tmp/execute-request.json || true)"
echo "Authorized staging attempt $attempt returned HTTP $status"
cat /tmp/execute-response.json

if [ "$status" = "200" ] && jq -e '
.event.status == "executed" and
.event.executor_invoked == true and
.receipt.status == "executed" and
(.event.evidence_sha256 | type == "string") and
(.event.evidence_sha256 | length == 64)
' /tmp/execute-response.json >/dev/null 2>&1; then
break
fi

if [ "$attempt" = "5" ]; then
echo "Authorized staging execution did not stabilize after five attempts"
exit 1
fi

if jq -e '
.event.status == "pact_stale" and
(.event.detail | test("Denied before executor invocation"; "i"))
' /tmp/execute-response.json >/dev/null 2>&1; then
echo "Live context drifted before execution; refreshing the Pact"
refresh_pact
continue
fi

echo "Authorized staging execution failed for a non-drift reason"
exit 1
done

jq -e '
.event.status == "executed" and
.event.executor_invoked == true and
.receipt.status == "executed" and
(.event.evidence_sha256 | type == "string") and
(.event.evidence_sha256 | length == 64)
' /tmp/execute-response.json

curl -fsS --max-time 120 -X POST "$IGRAPH_URL/v1/actions/execute" \
-H 'content-type: application/json' \
--data-binary @/tmp/execute-request.json | tee /tmp/replay-response.json
jq -e '
.event.status == "denied" and
.event.executor_invoked == false and
.receipt.status == "blocked" and
(.event.detail | test("Replay|duplicate|invocation limit"; "i"))
' /tmp/replay-response.json

- name: Prove signature tampering is blocked before execution
run: |
jq '.allowed_actions += ["deploy_production"]' /tmp/pact.json >/tmp/tampered-pact.json
Expand Down Expand Up @@ -244,7 +348,7 @@ jobs:
if: always()
run: |
mkdir -p /tmp/igraph-live-proof
for file in /tmp/health.json /tmp/datahub-health.txt /tmp/discover.json /tmp/analyze-request.json /tmp/analyze.json /tmp/verify.json /tmp/pact.json /tmp/tampered-pact.json /tmp/tampered-request.json /tmp/tampered-response.json /tmp/expired-pact.json /tmp/expired-request.json /tmp/expired-response.json /tmp/unavailable-health.json /tmp/unavailable-response.json /tmp/igraph.log /tmp/igraph-unavailable.log; do
for file in /tmp/health.json /tmp/datahub-health.txt /tmp/discover.json /tmp/analyze-request.json /tmp/analyze.json /tmp/verify.json /tmp/pact.json /tmp/execute-request.json /tmp/execute-response.json /tmp/replay-response.json /tmp/tampered-pact.json /tmp/tampered-request.json /tmp/tampered-response.json /tmp/expired-pact.json /tmp/expired-request.json /tmp/expired-response.json /tmp/unavailable-health.json /tmp/unavailable-response.json /tmp/igraph.log /tmp/igraph-unavailable.log; do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the target discovery response in the artifact

The new deterministic discovery request writes its evidence to /tmp/target-discover.json, but the collector omits that file. When the linked proof artifact is used to audit the documented claim that /v1/discover found order_items with lineage, it contains only the unrelated wildcard response and cannot substantiate that specific assertion; add the target response to this collection list.

Useful? React with 👍 / 👎.

if [ -f "$file" ]; then
cp "$file" /tmp/igraph-live-proof/
fi
Expand Down
29 changes: 17 additions & 12 deletions docs/DEVPOST_SUBMISSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,23 @@ validation states, and optional DataHub custom-property/Document write-back.

## What the recorded proof demonstrates

1. Live DataHub context is available and discovery returns 10 candidates.
2. The `addresses` context binds 28 downstream assets into a signed Impact Pact
with a high consequence score of 55/100.
3. A tampered Pact is denied before executor invocation.
4. An expired Pact is rejected as `pact_stale` before executor invocation.
5. Unavailable live context fails closed as `context_unavailable` / HTTP 503;
1. Live DataHub context is available and discovery selects a real showcase asset.
2. The selected `order_items` context contains 37 downstream assets and 3 dashboards,
producing a high-risk 55/100 signed Pact.
3. An explicitly approved `deploy_staging` action reaches only the reversible
staging simulator and returns an executed receipt with evidence.
4. Repeating the same signed request is denied before a second executor invocation.
5. A tampered Pact is denied before executor invocation.
6. An expired Pact is rejected as `pact_stale` before executor invocation.
7. Unavailable live context fails closed as `context_unavailable` / HTTP 503;
iGraph does not substitute fixture metadata.
8. Live post-read verification returns complete live context; it does not claim that
a real DataHub mutation occurred.

The 10-second video is a silent, deterministic vector reconstruction of the
control-room visual language, populated from the recorded proof artifact. It is
labeled as a reconstruction and does not claim a production deployment, real
database mutation, or DataHub write-back.
control-room visual language, populated from recorded proof data. It is labeled as
a reconstruction and does not claim a production deployment, real database
mutation, or DataHub write-back.

## Built with

Expand All @@ -39,13 +44,13 @@ database mutation, or DataHub write-back.
## Links to include

- Public source repository: `https://github.com/etvjay/iGraph`
- Live proof run: `https://github.com/etvjay/iGraph/actions/runs/31479477960`
- Live proof artifact: `https://github.com/etvjay/iGraph/actions/runs/31479477960/artifacts/9096775884`
- Live proof run: `https://github.com/etvjay/iGraph/actions/runs/31749044334`
- Live proof artifact: `https://github.com/etvjay/iGraph/actions/runs/31749044334/artifacts/9200418599`
- Reproducible request: [`examples/change-request.json`](../examples/change-request.json)
- Video asset: `igraph-demo-candidate.mp4` from the accompanying demo package

## Honest scope

The built-in executor is a reversible staging simulator. Production deployment,
real database mutation, and DataHub write-back remain outside this proof. The
live proof keeps `IGRAPH_ENABLE_WRITEBACK=false`.
live proof keeps `IGRAPH_ENABLE_WRITEBACK=false`.
40 changes: 25 additions & 15 deletions docs/LIVE_PROOF.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,42 @@
# iGraph live proof

This page records the public GitHub Actions proof for the merged iGraph code.
This page records the public GitHub Actions proof for the iGraph control plane.

## Merged code
## Code and checks

- Repository: https://github.com/etvjay/iGraph
- Main commit: `0136cef2fa556d79f7565999f77cfc92c0a66d42`
- Pull request: https://github.com/etvjay/iGraph/pull/2
- Post-merge CI: https://github.com/etvjay/iGraph/actions/runs/31618368233
- Main branch: https://github.com/etvjay/iGraph/tree/main
- Proof change: https://github.com/etvjay/iGraph/pull/4
- Ordinary CI for the proof branch: https://github.com/etvjay/iGraph/actions/runs/31749044332

## Recorded live results

The live-proof workflow ran against DataHub OSS and produced these results:
Live proof run #16 ran against DataHub OSS and produced these results:

- `/health`: `context_mode=live`, `datahub_configured=true`, write-back disabled.
- `/v1/discover`: 10 live candidates; the top candidate is `addresses` with
22 downstream assets and risk score 55.
- `/v1/analyze`: live `addresses` context with 28 downstream assets, complete
retrieval, high risk 55/100, and signed Pact `igp_ce855182f9dc`.
- `/v1/discover`: live wildcard discovery returned DataHub showcase assets, and the deterministic
`order_items` target was found with loaded lineage.
- `/v1/analyze`: signed Pact `igp_eb762f75370d` with context fingerprint
`db707cbee0416b60`, complete live retrieval, and staging scope requiring human approval.
The compiled context contained 37 downstream assets, 3 dashboards, and high risk 55/100.
- `/v1/verify`: live post-read verification returned `verified=true` with complete
retrieval. This was a re-read proof; no real DataHub mutation was attempted.
- Authorized staging action: with explicit approval, the reversible staging simulator
returned `executed`, `executor_invoked=true`, and a receipt with evidence hash
`14d0b81de9e6850255958da682bab0d0dc4f1534036752634ca07c6be0b21396`.
- Same-request replay: returned `denied` with `executor_invoked=false` because the
Pact invocation limit had already been consumed.
- Tampered Pact: `deny`, `executor_invoked=false`.
- Expired Pact: `pact_stale`, `executor_invoked=false`.
- Missing live context: `context_unavailable` / HTTP 503, with no fixture fallback.

Download the complete workflow artifact from the successful proof run:
https://github.com/etvjay/iGraph/actions/runs/31479477960/artifacts/9096775884
Download the complete proof artifact from run #16:
https://github.com/etvjay/iGraph/actions/runs/31749044334/artifacts/9200418599

## Claim boundary

This proves live reads, discovery, Pact signing, enforcement denial, expiry
rejection, and fail-closed behavior. It does not prove production deployment,
real database mutation, DataHub write-back, or a deployed public video.
This proves live reads, discovery, Pact signing, live post-read verification,
authorized reversible staging execution, one-shot replay protection, enforcement
denial, expiry rejection, and fail-closed behavior. It does not prove a real
database mutation, DataHub write-back, production deployment, or a deployed public
video.
Loading