Skip to content
Merged
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
44 changes: 43 additions & 1 deletion .github/workflows/reusable-drift-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,49 @@ jobs:
uses: actions/download-artifact@v4
with:
name: ${{ inputs.lifecycle_preflight_artifact }}
path: ${{ env.LIFECYCLE_LOCAL_ROOT }}
path: ${{ runner.temp }}/lifecycle-preflight

- name: Restore lifecycle preflight inputs
if: inputs.lifecycle_preflight_artifact != ''
env:
PREFLIGHT_BUNDLE_ROOT: ${{ runner.temp }}/lifecycle-preflight
SNAPSHOT_CHECKOUT_PATH: ${{ inputs.snapshot_checkout_path }}
shell: bash
run: |
set -euo pipefail
case "$SNAPSHOT_CHECKOUT_PATH" in
external/*) ;;
*) echo "::error::snapshot_checkout_path must remain under external/"; exit 1 ;;
esac
if [[ "$SNAPSHOT_CHECKOUT_PATH" == *".."* ]]; then
echo "::error::snapshot_checkout_path must not contain traversal segments"
exit 1
fi
if find "$PREFLIGHT_BUNDLE_ROOT" -type l -print -quit | grep -q .; then
echo "::error::lifecycle preflight artifact must not contain symlinks"
exit 1
fi
lifecycle_source="$PREFLIGHT_BUNDLE_ROOT/data/lifecycle_store"
snapshot_source="$PREFLIGHT_BUNDLE_ROOT/$SNAPSHOT_CHECKOUT_PATH/data/output"
if [ ! -d "$lifecycle_source" ] || [ ! -d "$snapshot_source" ]; then
echo "::error::lifecycle preflight artifact is missing required allowlisted directories"
exit 1
fi
snapshot_root="$GITHUB_WORKSPACE/$SNAPSHOT_CHECKOUT_PATH"
resolved_snapshot_root="$(realpath "$snapshot_root")"
case "$resolved_snapshot_root" in
"$GITHUB_WORKSPACE"/external/*) ;;
*) echo "::error::snapshot checkout resolved outside the external workspace"; exit 1 ;;
esac
if find "$snapshot_root" -type l -print -quit | grep -q .; then
echo "::error::snapshot checkout must not contain symlinks"
exit 1
fi
snapshot_target="$snapshot_root/data/output"
rm -rf -- "$LIFECYCLE_LOCAL_ROOT" "$snapshot_target"

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 Validate lifecycle restore path before deleting

When the caller checkout contains a symlinked data directory or other parent of data/lifecycle_store, this rm -rf resolves through that symlink because only the snapshot checkout is realpath/symlink-validated above. In scheduled/workflow_dispatch runs for such a repo, the restore can delete and then overwrite files outside the workspace; please add the same destination validation for $LIFECYCLE_LOCAL_ROOT before removing or copying into it.

Useful? React with 👍 / 👎.

mkdir -p "$LIFECYCLE_LOCAL_ROOT" "$GITHUB_WORKSPACE/$SNAPSHOT_CHECKOUT_PATH/data/output"
cp -a "$lifecycle_source/." "$LIFECYCLE_LOCAL_ROOT/"
cp -a "$snapshot_source/." "$snapshot_target/"

- name: Build lifecycle performance snapshots
run: quant-lifecycle monitor --domain ${{ inputs.strategy_domain }}
Expand Down
8 changes: 8 additions & 0 deletions tests/test_reusable_drift_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ def test_reusable_drift_workflow_enforces_lifecycle_preflight() -> None:
assert "Download lifecycle preflight artifact" in workflow
assert "actions/download-artifact@v4" in workflow
assert "name: ${{ inputs.lifecycle_preflight_artifact }}" in workflow
assert "path: ${{ runner.temp }}/lifecycle-preflight" in workflow
assert "Restore lifecycle preflight inputs" in workflow
assert "snapshot_checkout_path must remain under external/" in workflow
assert "lifecycle preflight artifact must not contain symlinks" in workflow
assert "snapshot checkout resolved outside the external workspace" in workflow
assert "snapshot checkout must not contain symlinks" in workflow
assert 'rm -rf -- "$LIFECYCLE_LOCAL_ROOT" "$snapshot_target"' in workflow
assert 'cp -a "$lifecycle_source/." "$LIFECYCLE_LOCAL_ROOT/"' in workflow
assert 'GH_TOKEN: ${{ github.token }}' in workflow
assert 'os.environ["CODEX_AUDIT_ORG"] = owner' in workflow
assert 'os.environ["CODEX_AUDIT_ORCHESTRATOR_REPO"] = repository' in workflow
Expand Down
Loading