Skip to content

fix(release): retain Binding RC evidence without brace globs - #316

Merged
DecisionNerd merged 2 commits into
mainfrom
fix/192-evidence-artifact-path
Aug 1, 2026
Merged

DecisionNerd merged 2 commits into
mainfrom
fix/192-evidence-artifact-path

Conversation

@DecisionNerd

@DecisionNerd DecisionNerd commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Binding RC @ 9736041 completed offline rehearsal and candidate validation (release-candidate: valid … nodes=24), then failed only on evidence artifact retention.
  • actions/upload-artifact does not expand candidate/release-artifacts/{evidence,node-addons}/; switch to an explicit multiline path.
  • Update the CI storage-policy allowlist/parser for block-scalar paths.

Related to #192 (does not close the release tracker).

Test plan

  • python3 scripts/ci/test-ci-storage-policy.py
  • Binding RC green on the merge SHA (evidence partition retained)

Made with Cursor


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of multiline configuration values in validation checks.
    • Updated artifact upload path validation to recognize approved evidence and native module paths correctly.

Note

Fix Binding RC evidence upload by replacing brace glob with explicit multiline paths

  • upload-artifact does not expand bash brace globs, so candidate/release-artifacts/{evidence,node-addons}/ was not uploading both directories.
  • binding-release-candidate.yml now lists evidence/ and node-addons/ as separate lines in a YAML block scalar.
  • The field parser in test-ci-storage-policy.py is updated to handle YAML block scalars (|, |-, >, >-) and return the last matching field when duplicates exist.
  • The artifact contract allowlist is updated to match the new multiline path format.

Macroscope summarized 219e8ee.

upload-artifact does not expand bash brace patterns, so the evidence
partition upload found zero files after a green offline rehearsal. List
evidence/ and node-addons/ explicitly.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation ci-cd CI/CD configuration changes tooling Developer tooling and automation release:none No release note or version impact labels Aug 1, 2026
@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The CI storage policy test now parses multiline YAML block-scalar fields and validates artifact upload paths using multiline evidence and node-addon directory values.

Changes

Storage policy validation

Layer / File(s) Summary
Multiline field parsing and artifact path contract
scripts/ci/test-ci-storage-policy.py
field now collects indented continuation lines for multiline YAML values. The approved artifact path representation now lists the evidence and node-addon directories on separate lines.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description explains the issue and test plan but omits most required template sections, including change type, checklist, performance, and breaking changes. Complete the repository template by adding the change type, detailed changes, testing details, checklist confirmations, performance impact, breaking-change status, and reviewer notes.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the release-candidate evidence retention fix and matches the main changes.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/192-evidence-artifact-path

Comment @coderabbitai help to get the list of available commands.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ci/test-ci-storage-policy.py`:
- Around line 135-145: Update the scalar handling in the policy parser around
the value check to reject folded YAML scalars ("?>" and ">-") unless their YAML
folding semantics are correctly implemented; preferably restrict accepted
artifact path blocks to literal styles "|" and "|-". Preserve the existing
collection behavior for supported literal scalars and add or update tests to
cover rejection of folded styles.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 36d1ca8a-fe91-480d-a39f-8483025b3706

📥 Commits

Reviewing files that changed from the base of the PR and between 7b8c76a and ebba43f.

⛔ Files ignored due to path filters (3)
  • .github/workflows/binding-release-candidate.yml is excluded by !**/.github/**
  • CHANGELOG.md is excluded by !**/*.md
  • docs/reference/changelog.md is excluded by !**/*.md, !**/docs/**
📒 Files selected for processing (1)
  • scripts/ci/test-ci-storage-policy.py

Comment on lines +135 to +145
if value in {"|", "|-", ">", ">-"}:
indent = len(line) - len(line.lstrip())
collected: list[str] = []
for follow in step[index + 1 :]:
if not follow.strip():
continue
follow_indent = len(follow) - len(follow.lstrip())
if follow_indent <= indent:
break
collected.append(follow.strip())
matched = "\n".join(collected)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

while IFS= read -r file; do
  rg -n -C 4 '^[[:space:]-]*(path|pattern|name):[[:space:]]*>-?[[:space:]]*$' "$file" || true
done < <(fd -t f -e yml -e yaml .)

Repository: CurateLabs/graphforge

Length of output: 211


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- target context ---'
sed -n '100,175p' scripts/ci/test-ci-storage-policy.py

printf '%s\n' '--- YAML files ---'
git ls-files '*.yml' '*.yaml' | sort

printf '%s\n' '--- folded scalar candidates ---'
while IFS= read -r file; do
  grep -n -E '^[[:space:]-]*(path|pattern|name):[[:space:]]*>-?[[:space:]]*$' "$file" || true
done < <(git ls-files '*.yml' '*.yaml')

printf '%s\n' '--- parser references ---'
grep -n -E 'def field|field\(|artifact|upload-artifact|path:' scripts/ci/test-ci-storage-policy.py

Repository: CurateLabs/graphforge

Length of output: 6465


🏁 Script executed:

set -euo pipefail

sed -n '135,230p' scripts/ci/test-ci-storage-policy.py

git ls-files '*.yml' '*.yaml' > /tmp/graphforge-yaml-files
printf '%s\n' '--- folded scalar candidates ---'
while IFS= read -r file; do
  grep -n -E '^[[:space:]-]*(path|pattern|name):[[:space:]]*>-?[[:space:]]*$' "$file" || true
done < /tmp/graphforge-yaml-files

printf '%s\n' '--- artifact path declarations ---'
while IFS= read -r file; do
  grep -n -E '^[[:space:]-]*path:' "$file" || true
done < /tmp/graphforge-yaml-files

printf '%s\n' '--- tests and callers ---'
grep -RIn -E 'artifact_contracts|def field|field\(' -- scripts tests 2>/dev/null | head -200 || true

Repository: CurateLabs/graphforge

Length of output: 15161


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- relevant workflow block ---'
sed -n '600,640p' .github/workflows/m1-release-certification.yml

printf '%s\n' '--- literal and folded path scalar headers in workflows ---'
git ls-files '.github/workflows/*.yml' '.github/workflows/*.yaml' > /tmp/graphforge-workflows
while IFS= read -r file; do
  grep -n -E '^[[:space:]-]*path:[[:space:]]*[|>][-+]?[[:space:]]*$' "$file" || true
done < /tmp/graphforge-workflows

printf '%s\n' '--- behavioral probe for the exact field logic ---'
python3 - <<'PY'
def field(step: list[str], name: str) -> str | None:
    matched: str | None = None
    for index, line in enumerate(step):
        stripped = line.strip().removeprefix("- ")
        if not stripped.startswith(name + ":"):
            continue
        value = stripped.split(":", 1)[1].strip().strip("'\"")
        if value in {"|", "|-", ">", ">-"}:
            indent = len(line) - len(line.lstrip())
            collected: list[str] = []
            for follow in step[index + 1:]:
                if not follow.strip():
                    continue
                follow_indent = len(follow) - len(follow.lstrip())
                if follow_indent <= indent:
                    break
                collected.append(follow.strip())
            matched = "\n".join(collected)
        else:
            matched = value
    return matched

for indicator in ("|", "|-", ">", ">-"):
    step = [
        "      - uses: actions/upload-artifact@v7",
        f"        path: {indicator}",
        "          candidate/release-artifacts/evidence/",
        "          candidate/release-artifacts/node-addons/",
    ]
    print(indicator, repr(field(step, "path")))
PY

Repository: CurateLabs/graphforge

Length of output: 640


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- workflow files with literal path blocks ---'
git ls-files '.github/workflows/*.yml' '.github/workflows/*.yaml' | while IFS= read -r file; do
  grep -Hn -E '^[[:space:]-]*path:[[:space:]]*[|>][-+]?[[:space:]]*$' "$file" || true
done

printf '%s\n' '--- relevant literal block context ---'
git grep -n -A5 -B2 -E '^[[:space:]-]*path:[[:space:]]*\|[-+]?[[:space:]]*$' -- '.github/workflows/*.yml' '.github/workflows/*.yaml' | head -120

printf '%s\n' '--- behavioral probe for the exact field logic ---'
python3 - <<'PY'
def field(step, name):
    matched = None
    for index, line in enumerate(step):
        stripped = line.strip().removeprefix("- ")
        if not stripped.startswith(name + ":"):
            continue
        value = stripped.split(":", 1)[1].strip().strip("'\"")
        if value in {"|", "|-", ">", ">-"}:
            indent = len(line) - len(line.lstrip())
            collected = []
            for follow in step[index + 1:]:
                if not follow.strip():
                    continue
                follow_indent = len(follow) - len(follow.lstrip())
                if follow_indent <= indent:
                    break
                collected.append(follow.strip())
            matched = "\n".join(collected)
        else:
            matched = value
    return matched

for indicator in ("|", "|-", ">", ">-"):
    step = [
        "      - uses: actions/upload-artifact@v7",
        "        path: " + indicator,
        "          candidate/release-artifacts/evidence/",
        "          candidate/release-artifacts/node-addons/",
    ]
    print(indicator, repr(field(step, "path")))
PY

Repository: CurateLabs/graphforge

Length of output: 5795


Do not accept folded scalars without parsing their semantics.

field accepts > and >-, but joins content with \n. YAML folds ordinary lines to spaces. A future upload-artifact path: >- block could therefore pass a different value to the policy test than to GitHub Actions.

Restrict artifact path lists to | and |-, or implement folded-scalar semantics and add tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/test-ci-storage-policy.py` around lines 135 - 145, Update the
scalar handling in the policy parser around the value check to reject folded
YAML scalars ("?>" and ">-") unless their YAML folding semantics are correctly
implemented; preferably restrict accepted artifact path blocks to literal styles
"|" and "|-". Preserve the existing collection behavior for supported literal
scalars and add or update tests to cover rejection of folded styles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-cd CI/CD configuration changes documentation Improvements or additions to documentation release:none No release note or version impact tooling Developer tooling and automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant