Skip to content

Implement Phase 4: Pipeline workflow for SDLC checkpoints - #252

Merged
jwbron merged 9 commits into
mainfrom
egg/issue-133-phase-4
Feb 7, 2026
Merged

Implement Phase 4: Pipeline workflow for SDLC checkpoints#252
jwbron merged 9 commits into
mainfrom
egg/issue-133-phase-4

Conversation

@james-in-a-box

@james-in-a-box james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements Phase 4 of the SDLC structurally enforced checkpoints spec:

  • sdlc-pipeline.yml: Main pipeline workflow with init, refine, plan, implement, review, loop, and PR jobs
  • sdlc-hitl.yml: HITL decision workflow with 30-second debounce and phase approval handling
  • contract-state.sh: Contract state management script for pipeline operations

The pipeline orchestrates the implement→review cycle with automatic looping until all tasks pass or the circuit breaker trips.

Test plan

  • Verify YAML files pass yamllint (done locally, passes)
  • Verify shell script passes shellcheck (done locally, only style suggestions)
  • Verify contract tests still pass (done locally, 162 tests pass)
  • Review workflow triggers and job dependencies
  • Review HITL debounce logic
  • Manual test of pipeline with a real issue (Phase 5+ integration testing)

Issue: #133

Authored-by: egg

Add GitHub Actions workflows and supporting scripts for the SDLC
pipeline that orchestrates agent-based development with structurally
enforced checkpoints.

New files:
- .github/workflows/sdlc-pipeline.yml: Main pipeline workflow with jobs
  for init, refine, plan, implement, review, loop, and PR phases
- .github/workflows/sdlc-hitl.yml: HITL decision workflow that handles
  checkbox-based approvals with 30-second debounce
- action/contract-state.sh: Contract state management script for
  loading, updating, and checking contract state during pipeline runs

The pipeline implements:
- Automated init job that creates contracts and branches
- Phase-specific agent execution (refine, plan, implement, pr)
- Reviewer-implementer cycle with automatic looping
- Circuit breaker pattern with configurable thresholds
- HITL decision handling with debounce for rapid edits
- Phase approval via checkbox comments

Issue: #133

Authored-by: egg
@james-in-a-box

This comment has been minimized.

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Review: No concerns.

The design aligns well with agent-mode principles:

  • Prompts pass lightweight metadata (issue number, phase, branch) rather than pre-fetching large diffs
  • Agent invokes GitHub actions directly rather than outputting JSON for post-processing
  • Review prompts focus on objectives ("verify implementation meets acceptance criteria") rather than micromanaging procedure
  • Contract state management is legitimate workflow infrastructure, not agent output parsing

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Code Review: PR #252 — SDLC Pipeline Implementation

This PR adds three files implementing Phase 4 of the SDLC structurally enforced checkpoints. I've identified several security vulnerabilities and correctness issues that must be addressed before merge.


🔴 Critical Security Issues

1. Missing Authorization in sdlc-hitl.yml (HIGH SEVERITY)

File: .github/workflows/sdlc-hitl.yml
Lines: 18-296 (entire handle-decision and handle-approval jobs)

The HITL workflow triggers on issue_comment: [edited] but does not verify the sender's authorization. Any user who can edit a comment (which includes the original comment author) can:

  • Advance the pipeline to arbitrary phases
  • Resolve HITL decisions
  • Trigger the SDLC pipeline with arbitrary phase parameters

Compare to on-mention.yml (line 23) which correctly checks:

github.event.sender.login == 'jwbron' &&
github.event.sender.login != 'james-in-a-box'

Fix required: Add authorization check in the job if: condition:

if: >-
  contains(github.event.comment.body, '<!-- egg-hitl-decision') &&
  github.event.sender.login == 'jwbron' &&
  github.event.sender.login != 'james-in-a-box'

Apply the same fix to the handle-approval job.


2. Potential Command Injection via SELECTED_OPTION

File: .github/workflows/sdlc-hitl.yml
Lines: 66, 132, 260-274

The SELECTED_OPTION is extracted from user-controlled comment body via regex and passed to:

  • jq commands (line 156-163)
  • Issue comment bodies (lines 260-274)

While jq with --arg is generally safe from injection, the value is interpolated into the comment body using shell variable expansion:

BODY="Decision **${DECISION_ID}** resolved: ${SELECTED_OPTION}

If SELECTED_OPTION contains characters like backticks or $(...), this could lead to command execution in certain contexts.

Fix: Escape or validate SELECTED_OPTION before use, or use heredoc with proper quoting:

BODY=$(cat <<COMMENTEOF
Decision **${DECISION_ID}** resolved: ${SELECTED_OPTION}
...
COMMENTEOF
)

🟠 Medium Severity Issues

3. Race Condition in Contract Updates

File: .github/workflows/sdlc-hitl.yml
Lines: 126-194, 196-247

The workflow performs a read-modify-write cycle on the contract JSON file:

  1. Read contract
  2. Modify with jq
  3. Write to temp file
  4. Move to original location
  5. Git add/commit/push

Multiple concurrent workflow runs (e.g., rapid checkbox edits) can race:

  • Two runs read the same contract state
  • Both modify independently
  • Second commit overwrites first's changes

The debounce mechanism (lines 77-99) is insufficient because:

  1. It waits AFTER checking, so two runs can both decide to proceed
  2. The check counts "in_progress" runs but doesn't prevent overlapping writes

Fix: Use git-level locking or atomic operations. Consider git pull --rebase before push, and retry on conflict.


4. Missing set -euo pipefail in Inline Shell Scripts

File: .github/workflows/sdlc-hitl.yml and .github/workflows/sdlc-pipeline.yml

The inline run: scripts don't include set -euo pipefail. This means:

  • Commands can fail silently
  • Unset variables won't cause errors
  • Pipelines won't propagate failures

Example problematic pattern (sdlc-pipeline.yml, line 88):

ISSUE_TITLE=$(echo "$ISSUE_DATA" | jq -r '.title')

If gh api fails and ISSUE_DATA is empty, jq returns "null" rather than failing.

Fix: Add set -euo pipefail at the start of each run: block, or use a shell wrapper.


5. Debounce Logic Bug

File: .github/workflows/sdlc-hitl.yml
Lines: 77-99

The debounce implementation has a logic flaw:

if [[ "$RECENT_RUNS" -gt "1" ]]; then
  echo "should_process=false" >> "$GITHUB_OUTPUT"
else
  echo "should_process=true" >> "$GITHUB_OUTPUT"
fi

# Wait for debounce period
echo "Waiting ${DEBOUNCE_SECONDS}s for debounce..."
sleep "$DEBOUNCE_SECONDS"

The sleep happens AFTER the decision, not during the window where new edits should reset the timer. This doesn't implement proper debounce semantics.

Expected behavior: Wait for DEBOUNCE_SECONDS of quiescence (no new edits), then process.
Actual behavior: Always wait 30 seconds, even if the decision was "don't process."


6. Integer Comparison Issues

File: .github/workflows/sdlc-hitl.yml
Line: 90

if [[ "$RECENT_RUNS" -gt "1" ]]; then

If the jq filter returns empty or non-numeric output, bash's -gt comparison will fail.

Fix: Add default value handling:

RECENT_RUNS=${RECENT_RUNS:-0}
if [[ "$RECENT_RUNS" =~ ^[0-9]+$ ]] && [[ "$RECENT_RUNS" -gt "1" ]]; then

Same issue exists in sdlc-pipeline.yml line 417:

if [[ "$TOTAL_CYCLES" -ge "$MAX_CYCLES" ]]; then

🟡 Lower Severity Issues

7. Hardcoded Bot Username

Files: Both workflow files

BOT_USERNAME: james-in-a-box is hardcoded in multiple places. If the bot identity changes, multiple locations need updating.

Fix: Define once and reference, or use a repository variable.


8. Missing Concurrency Control

File: .github/workflows/sdlc-pipeline.yml

Unlike on-mention.yml which has:

concurrency:
  group: egg-mention-${{ github.event.issue.number }}
  cancel-in-progress: false

The sdlc-pipeline.yml lacks concurrency controls. Multiple pipeline runs for the same issue could conflict.


9. Audit Log Records Wrong Old Value

File: .github/workflows/sdlc-hitl.yml
Lines: 371-381

.audit_log += [{
  ...
  old_value: .current_phase,  // This captures the NEW value, not old
  new_value: $phase,
  ...
}]

Since jq evaluates expressions after the assignment, .current_phase already contains $phase at audit log time.

Fix: Capture old phase before the update:

OLD_PHASE=$(jq -r '.current_phase' "$CONTRACT_PATH")
jq --arg phase "$NEXT_PHASE" --arg old "$OLD_PHASE" ...

10. Contract Path Traversal Risk

File: Both workflow files

The contract path is constructed from ISSUE_NUMBER:

CONTRACT_PATH=".egg-state/contracts/${ISSUE_NUMBER}.json"

If ISSUE_NUMBER contains path components like ../, it could access files outside the intended directory. While GitHub's API would return an error for non-numeric issue numbers, the workflow_dispatch input accepts user input.

Fix: Validate issue number is numeric:

if ! [[ "$ISSUE_NUMBER" =~ ^[0-9]+$ ]]; then
  echo "Invalid issue number"
  exit 1
fi

11. Python Dependencies Not Pinned

File: .github/workflows/sdlc-pipeline.yml
Lines: 66-67

run: |
  pip install pydantic pyyaml

Unpinned dependencies risk:

  • Supply chain attacks
  • Reproducibility issues
  • Breaking changes

Fix: Pin to specific versions or use a requirements file.


12. No Error Handling for gh workflow run

File: .github/workflows/sdlc-hitl.yml
Lines: 280-282, 415-417

gh workflow run sdlc-pipeline.yml \
  --field issue_number="${ISSUE_NUMBER}" \
  --field starting_phase="${NEXT_PHASE}"

If this fails, no error is reported and the issue is left in an inconsistent state.


Summary

Blocking issues that must be fixed:

  1. Missing authorization check in sdlc-hitl.yml (security vulnerability)
  2. Race condition in contract updates (data corruption risk)

Should be fixed:
3. Command injection risk with SELECTED_OPTION
4. Add set -euo pipefail to shell scripts
5. Fix debounce logic
6. Add integer validation
7-12. Remaining issues


— Authored by egg

- Remove unused CURRENT_TIME variable (SC2034) in sdlc-hitl.yml
- Group consecutive redirects to GITHUB_OUTPUT (SC2129) in sdlc-hitl.yml
- Group consecutive redirects to GITHUB_OUTPUT (SC2129) in sdlc-pipeline.yml

Authored-by: egg
@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

@james-in-a-box

This comment has been minimized.

@james-in-a-box

This comment has been minimized.

@jwbron

jwbron commented Feb 7, 2026

Copy link
Copy Markdown
Owner

@james-in-a-box address the above feedback #252 (review)

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Review: No concerns.

Since the original commit was force-pushed away, I performed a full review of the current implementation. The design aligns well with agent-mode principles:

  • Lightweight context, not pre-fetching: build-sdlc-prompt.sh passes minimal metadata (issue number, phase, branch, truncated issue body up to 10KB) rather than baking in large diffs or file contents. The agent explores the codebase on its own.

  • Agent takes actions directly: The workflows invoke the egg action, which lets the agent post comments, push code, and create PRs itself. No JSON output parsing or post-processing pipelines.

  • Objectives over procedures: Phase prompts describe what outcome is wanted (e.g., "Create a detailed implementation plan") with context about available capabilities, but don't micromanage step-by-step procedures.

  • Contract state is workflow infrastructure: The contract JSON and contract-state.sh track pipeline state (current phase, task completion). This is workflow coordination infrastructure—analogous to CI systems tracking build state—not agent output parsing.

  • HITL workflow is valid oversight infrastructure: The sdlc-hitl.yml handles human approvals via checkbox edits. This is legitimate human-in-the-loop infrastructure, not a constraint on agent flexibility.

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-Review: PR #252 — SDLC Pipeline Implementation

Previous review at commit: 063906f289d6870768cb50e12768a4145ce8eaa1
Current review at commit: e5521ba47ed1c7006f7db62c1ef69201dc39d9ee

The new commit claims to "Fix shellcheck warnings" (removing unused variable, grouping redirects), but none of the critical security issues from my previous review have been addressed.


🔴 CRITICAL: Blocking Issues NOT Fixed

1. Missing Authorization Check in sdlc-hitl.yml (STILL PRESENT)

File: .github/workflows/sdlc-hitl.yml
Lines: 22, 296

Both handle-decision and handle-approval jobs still lack authorization checks. Compare to on-mention.yml which correctly requires:

github.event.sender.login == 'jwbron' &&
github.event.sender.login != 'james-in-a-box'

The current code allows any user who can edit a comment to:

  • Advance the pipeline to arbitrary phases
  • Resolve HITL decisions
  • Trigger workflow execution

Required fix:

# handle-decision job
if: >-
  contains(github.event.comment.body, '<!-- egg-hitl-decision') &&
  github.event.sender.login == 'jwbron' &&
  github.event.sender.login != 'james-in-a-box' &&
  github.event.sender.login != 'james-in-a-box[bot]'

# handle-approval job
if: >-
  !contains(github.event.comment.body, '<!-- egg-hitl-decision') &&
  (
    contains(github.event.comment.body, '<!-- egg-phase-approval') ||
    contains(github.event.comment.body, '[x] Approve')
  ) &&
  github.event.sender.login == 'jwbron' &&
  github.event.sender.login != 'james-in-a-box' &&
  github.event.sender.login != 'james-in-a-box[bot]'

2. Race Condition in Contract Updates (STILL PRESENT)

Files: .github/workflows/sdlc-hitl.yml, .github/workflows/sdlc-pipeline.yml

Multiple workflow runs can race on read-modify-write cycles to the contract JSON. The debounce mechanism doesn't prevent this — two runs can both read the same state, both decide to proceed, then overwrite each other's changes.

Required fix: Add git pull --rebase before push operations, or use GitHub Actions concurrency controls:

concurrency:
  group: sdlc-contract-${{ github.event.issue.number }}
  cancel-in-progress: false

3. Audit Log Records Wrong Old Value (STILL PRESENT)

File: .github/workflows/sdlc-hitl.yml
Lines: 371-386

jq --arg phase "$NEXT_PHASE" \
  ...
  'old_value: .current_phase,  # ← This captures the NEW value, not old
   new_value: $phase,

The jq expression evaluates .current_phase AFTER the assignment on the same line, capturing the new value in both fields.

Required fix:

OLD_PHASE=$(jq -r '.current_phase' "$CONTRACT_PATH")
jq --arg phase "$NEXT_PHASE" --arg old "$OLD_PHASE" \
  '.current_phase = $phase |
   .audit_log += [{
     ...
     old_value: $old,
     new_value: $phase,
   }]'

🟠 Medium Severity Issues NOT Fixed

4. Missing Concurrency Control in sdlc-pipeline.yml

Unlike on-mention.yml, the pipeline workflow lacks concurrency controls. Multiple pipeline runs for the same issue could conflict.

5. Contract Path Traversal Risk

ISSUE_NUMBER from workflow_dispatch input is not validated as numeric before constructing file paths.

6. Unpinned Python Dependencies

pip install pydantic pyyaml without version pins (line 67 of sdlc-pipeline.yml).

7. No Error Handling for gh workflow run

Failed workflow triggers leave the issue in an inconsistent state with no error reporting.


What WAS Fixed

The commit message claims:

  • Remove unused CURRENT_TIME variable (SC2034)
  • Group consecutive redirects to GITHUB_OUTPUT (SC2129)

However, reviewing the current file content, I don't see evidence these changes were applied. The grouped redirect pattern ({ echo "x"; echo "y"; } >> "$GITHUB_OUTPUT") appears in only one place (lines 395-399), and there's no CURRENT_TIME variable visible. It's possible these are legitimate fixes that I can't verify from the diff, but the security issues remain the priority.


Summary

This PR should not be merged until the following are addressed:

  1. Add authorization checks to both HITL jobs (security vulnerability)
  2. Add concurrency controls to prevent race conditions (data corruption risk)
  3. Fix audit log old_value capture (correctness issue)
  4. Add issue number validation (path traversal defense)

(Unable to formally request changes since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

The check-workflow-secrets.py linter detected that action/contract-state.sh
was being executed with GH_TOKEN after checking out an untrusted PR branch.
This is a security vulnerability as a malicious PR could modify the script.

Fix by saving the action/ directory to $RUNNER_TEMP/trusted-action after
the trusted main checkout, then running scripts from that saved copy after
the untrusted branch checkout.

Affected jobs: implement, review

Authored-by: egg
@james-in-a-box

This comment has been minimized.

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Re-Review: No concerns.

Changes since last review (e5521ba77cb2f2): The new commit fixes a workflow secret safety issue by saving trusted action scripts before checking out untrusted PR branches. This is a security hardening change, not an agent-mode design modification.

The original design assessment remains valid:

  • Lightweight context: build-sdlc-prompt.sh passes minimal orientation metadata (issue number, phase, branch, truncated issue body up to 10KB) rather than pre-fetching large diffs or file contents
  • Agent takes actions directly: The egg action lets the agent post comments, push code, and create PRs itself—no JSON parsing or post-processing pipelines
  • Objectives over procedures: Phase prompts describe desired outcomes with helpful context about capabilities and restrictions, without micromanaging step-by-step procedures
  • Contract state is infrastructure: The contract JSON tracks pipeline coordination state (current phase, task completion), analogous to CI build state—this is workflow infrastructure, not agent output parsing

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

Security fixes:
- Add authorization checks to sdlc-hitl.yml (only jwbron can trigger)
- Fix command injection risk with SELECTED_OPTION using printf
- Add issue number validation (path traversal prevention)
- Add error handling for gh workflow run commands

Correctness fixes:
- Fix race condition with retry logic and git pull --rebase
- Fix debounce logic (wait before decision, not after)
- Fix audit log capturing wrong old_value in handle-approval
- Add integer validation for RECENT_RUNS, TOTAL_CYCLES, MAX_CYCLES
- Add set -euo pipefail to shell scripts

Other improvements:
- Add concurrency control to sdlc-pipeline.yml
- Pin Python dependencies (pydantic, pyyaml)

Addresses review feedback from PR #252.

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Response to code review feedback:

✅ Fixed Issues

Critical Security Issues

#1 - Missing Authorization: Added sender authorization checks to both handle-decision and handle-approval jobs, matching the pattern from on-mention.yml.

#2 - Command Injection: Replaced shell variable interpolation with printf to safely construct comment bodies from user-controlled SELECTED_OPTION.

Medium Severity Issues

#3 - Race Condition: Added retry logic with git pull --rebase before push (up to 3 attempts) to handle concurrent contract updates.

#4 - Missing set -euo pipefail: Added to all key shell script blocks in both workflow files.

#5 - Debounce Logic Bug: Reordered debounce to wait FIRST (for edits to settle), then check for concurrent runs.

#6 - Integer Comparison Issues: Added numeric validation with default fallback for RECENT_RUNS, TOTAL_CYCLES, and MAX_CYCLES.

Lower Severity Issues

#7 - Hardcoded Bot Username: Deferred to follow-up. Would require defining a repository variable and updating multiple files.

#8 - Missing Concurrency Control: Added concurrency block to sdlc-pipeline.yml keyed on issue number.

#9 - Audit Log Wrong Old Value: Fixed by capturing CURRENT_PHASE in a shell variable before the jq update, then passing via --arg old_phase.

#10 - Contract Path Traversal: Added numeric validation for ISSUE_NUMBER before constructing paths.

#11 - Python Dependencies Not Pinned: Pinned to pydantic==2.10.* and pyyaml==6.0.*.

#12 - Error Handling for gh workflow run: Added set -euo pipefail and explicit error check with ::error:: annotation.

All changes pushed in commit 6a1038f.

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg finished successfully. View run logs

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg is investigating the Lint check failure...

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Re-Review: No concerns.

Changes since last review (77cb2f26a1038f): The new commit addresses security and correctness issues from the base code review—authorization checks, set -euo pipefail, numeric validation, retry logic for git push, concurrency controls, audit log fixes, and dependency pinning.

None of these changes affect agent-mode design. They are workflow infrastructure hardening, not modifications to how the agent is invoked, what context it receives, or how its output is handled.

The original design assessment remains valid:

  • Lightweight context: build-sdlc-prompt.sh passes minimal orientation metadata rather than pre-fetching large diffs or file contents
  • Agent takes actions directly: The egg action lets the agent post comments, push code, and create PRs—no JSON parsing or post-processing
  • Objectives over procedures: Phase prompts describe desired outcomes with helpful context, without micromanaging step-by-step procedures
  • Contract state is infrastructure: The contract JSON tracks pipeline coordination state, analogous to CI build state—this is workflow infrastructure, not agent output parsing

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

Re-Review: PR #252 — SDLC Pipeline Implementation

Previous review at commit: e5521ba47ed1c7006f7db62c1ef69201dc39d9ee
Current review at commit: 6a1038f2c5f200e0d13e63c9b7c6b6c21354b040

This commit claims to address the security and correctness issues from my previous review. I've verified each fix and identified new issues introduced by the changes.


✅ Issues Properly Fixed

1. Authorization Checks (Critical - FIXED)

Both handle-decision and handle-approval jobs now correctly include authorization checks:

github.event.sender.login == 'jwbron' &&
github.event.sender.login != 'james-in-a-box' &&
github.event.sender.login != 'james-in-a-box[bot]'

2. Command Injection Prevention (FIXED)

The Post status comment step now uses printf to safely construct comment bodies.

3. Retry Logic for Race Conditions (FIXED)

Push operations now include retry logic with git pull --rebase.

4. Debounce Logic (FIXED)

The sleep now occurs BEFORE the concurrent run check.

5. Integer Validation (FIXED)

Added numeric validation for RECENT_RUNS, TOTAL_CYCLES, and MAX_CYCLES.

6. Issue Number Validation (FIXED)

Path traversal prevention added to both workflows.

7. Concurrency Control (FIXED)

sdlc-pipeline.yml now includes concurrency controls.

8. Audit Log Old Value (FIXED)

The handle-approval job now correctly captures the old phase before the jq update.

9. Error Handling for gh workflow run (FIXED)

10. Python Dependencies Pinned (FIXED)

Now uses pydantic==2.10.* pyyaml==6.0.*.

11. set -euo pipefail Added (FIXED)


🔴 NEW ISSUES Found

1. Retry Loop Logic Bug (sdlc-hitl.yml lines 221-238)

MAX_RETRIES=3
for i in $(seq 1 $MAX_RETRIES); do
  if git push origin "${BRANCH_NAME}"; then
    echo "Push succeeded"
    break
  else
    echo "Push failed (attempt $i/$MAX_RETRIES), trying rebase..."
    git pull --rebase origin "${BRANCH_NAME}" || {
      echo "Rebase failed, cannot resolve conflict automatically"
      echo "contract_updated=false" >> "$GITHUB_OUTPUT"
      exit 1
    }
  fi
  if [[ $i -eq $MAX_RETRIES ]]; then  # ← This check is INSIDE the loop
    echo "Push failed after $MAX_RETRIES attempts"
    echo "contract_updated=false" >> "$GITHUB_OUTPUT"
    exit 1
  fi
done

Problem: The max retries check if [[ $i -eq $MAX_RETRIES ]] occurs INSIDE the loop, meaning if the push fails on attempt 3, the rebase runs, then the max retry check fails BEFORE attempting the final push. This effectively limits to 2 retry attempts, not 3.

Fix: Restructure the loop:

for i in $(seq 1 $MAX_RETRIES); do
  if git push origin "${BRANCH_NAME}"; then
    echo "Push succeeded"
    break
  elif [[ $i -eq $MAX_RETRIES ]]; then
    echo "Push failed after $MAX_RETRIES attempts"
    echo "contract_updated=false" >> "$GITHUB_OUTPUT"
    exit 1
  else
    echo "Push failed (attempt $i/$MAX_RETRIES), trying rebase..."
    git pull --rebase origin "${BRANCH_NAME}" || {
      echo "Rebase failed"
      exit 1
    }
  fi
done

The same bug exists at:

  • sdlc-hitl.yml lines 289-297
  • sdlc-hitl.yml lines 462-468

2. Inconsistent Retry Logic

The second retry loop in Check for phase advancement lacks the detailed error handling of the first. Should be consistent.

3. Missing Retry Logic in loop job (sdlc-pipeline.yml)

The Check loop condition step pushes without retry logic at lines 468-471 and 482-485:

git add "$CONTRACT_PATH"
git commit -m "Open circuit breaker after ${TOTAL_CYCLES} cycles"
git push origin "${BRANCH_NAME}"

This is vulnerable to the same race condition that the retry logic was added to prevent.

4. Missing Retry Logic in create-pr job (sdlc-pipeline.yml lines 503-506)

Same issue - no retry logic for push.

5. Post approval comment still uses direct interpolation (sdlc-hitl.yml lines 483-489)

While Post status comment was fixed to use printf, the Post approval comment step still uses direct variable interpolation. For consistency and defense in depth, this should also use printf.


🟡 Minor Issues

6. sdlc-hitl.yml lacks concurrency control

While sdlc-pipeline.yml now has concurrency controls, sdlc-hitl.yml still lacks them.


Summary

The commit successfully addresses the critical security issues from my previous review. The remaining issues are correctness bugs in the retry loop logic and missing retry logic in other locations.

Must fix:

  1. Retry loop logic bug (3 locations)
  2. Missing retry logic in loop and create-pr jobs (3 push operations)

Should fix:
3. Post approval comment should use printf
4. Add concurrency to sdlc-hitl.yml

(Unable to formally request changes since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

Replace unused loop variable `i` with `_` in retry loops to silence
shellcheck warnings about unused variables.

Authored-by: egg
@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg autofix completed. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Re-Review: No concerns.

Changes since last review (6a1038f0a10e83): The new commit fixes shellcheck SC2034 warnings (unused variables). This is a code quality fix that doesn't affect agent-mode design.

The design continues to align well with agent-mode principles:

  • Lightweight context: build-sdlc-prompt.sh passes minimal orientation metadata (issue number, phase, branch, truncated issue body up to 10KB) rather than pre-fetching large diffs or file contents
  • Agent takes actions directly: The egg action lets the agent post comments, push code, and create PRs itself—no JSON parsing or post-processing pipelines
  • Objectives over procedures: Phase prompts describe desired outcomes with helpful context about capabilities and restrictions, without micromanaging step-by-step procedures
  • Contract state is infrastructure: The contract JSON tracks pipeline coordination state (current phase, task completion), analogous to CI build state—this is workflow infrastructure, not agent output parsing
  • HITL workflow is valid oversight: The sdlc-hitl.yml handles human approvals via checkbox edits—legitimate human-in-the-loop infrastructure

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

Agreed. Added retry logic to the init job's "Push branch" step (sdlc-pipeline.yml:160-179) to match the pattern used in other push operations.

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg finished successfully. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Re-Review: No concerns.

Changes since last review (171270e2020cb0): Added retry logic to the init job's "Push branch" step, addressing the minor note from my previous review. This is infrastructure hardening, not an agent-mode design change.

The design continues to align well with agent-mode principles. No concerns.

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

jwbron
jwbron previously approved these changes Feb 7, 2026
@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-Review: PR #252 — SDLC Pipeline Implementation

Previous review at commit: 171270e0f414d87331a706a7a7e12075fc8999aa
Current review at commit: 2020cb0d1dc585bbb2e5e2971626976b9d363f05

The new commit addresses my previous minor note about missing retry logic in the init job's "Push branch" step.


✅ New Change Verified

Retry Logic Added to Init Job Push (FIXED)

sdlc-pipeline.yml:160-181 now includes proper retry logic:

MAX_RETRIES=3
for i in $(seq 1 $MAX_RETRIES); do
  if git push -u origin "${BRANCH_NAME}"; then
    echo "Push succeeded"
    break
  elif [[ $i -eq $MAX_RETRIES ]]; then
    echo "Push failed after $MAX_RETRIES attempts"
    exit 1
  else
    echo "Push failed (attempt $i/$MAX_RETRIES), trying rebase..."
    git pull --rebase origin "${BRANCH_NAME}" || {
      echo "Rebase failed, cannot resolve conflict automatically"
      exit 1
    }
  fi
done

This correctly uses the elif pattern that ensures all 3 push attempts are made, consistent with the other retry loops in the codebase.


🔴 NEW ISSUE: Missing set -euo pipefail in Init Job Push Step

The new retry logic in the "Push branch" step (lines 160-181) lacks set -euo pipefail. While other steps in the workflow include this, the push step does not:

- name: Push branch
  env:
    GH_TOKEN: ${{ steps.bot-token.outputs.token }}
    BRANCH_NAME: ${{ steps.setup.outputs.branch_name }}
  run: |
    # Retry push with rebase on conflict  <-- Missing set -euo pipefail here
    MAX_RETRIES=3

Compare to other steps like Setup pipeline (line 82) and Check loop condition (line 422) which correctly include set -euo pipefail.

Risk: Without set -euo pipefail:

  • If BRANCH_NAME is unset or empty, the script will silently use an empty value instead of failing
  • Errors in the loop may not propagate correctly

Fix: Add set -euo pipefail at the start of the run block:

run: |
  set -euo pipefail
  # Retry push with rebase on conflict
  MAX_RETRIES=3
  ...

Summary

The init job retry logic is structurally correct, but lacks set -euo pipefail for consistency with other shell blocks in the workflow. This should be fixed before merge.

(Unable to formally request changes since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

@jwbron

jwbron commented Feb 7, 2026

Copy link
Copy Markdown
Owner

@james-in-a-box address the feedback here #252 (review)

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Added set -euo pipefail to the init job's "Push branch" step (sdlc-pipeline.yml:165) for consistency with other shell blocks in the workflow.

— Authored by egg

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Added set -euo pipefail to the init job's "Push branch" step (sdlc-pipeline.yml:165) for consistency with other shell blocks in the workflow.

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg finished successfully. View run logs

jwbron
jwbron previously approved these changes Feb 7, 2026
@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

Agent-Mode Design Re-Review: No concerns.

Changes since last review (2020cb03e25da9): Added set -euo pipefail to the init job's "Push branch" step. This is a shell safety fix, not an agent-mode design change.

No agent-mode design concerns. The design continues to align well with agent-mode principles.

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-Review: PR #252 — SDLC Pipeline Implementation

Previous review at commit: 2020cb0d1dc585bbb2e5e2971626976b9d363f05
Current review at commit: 3e25da90ee98abb35abcdafb8d4388c5e40c7873


✅ Issue Fixed

Missing set -euo pipefail in Init Job Push Step (FIXED)

The new commit correctly adds set -euo pipefail to the init job's "Push branch" step (sdlc-pipeline.yml:165), addressing the issue from my previous review:

- name: Push branch
  run: |
    set -euo pipefail
    # Retry push with rebase on conflict
    MAX_RETRIES=3
    ...

This ensures the script will:

  • Fail immediately on errors (-e)
  • Fail on unset variables (-u)
  • Fail on pipe errors (-o pipefail)

📝 Advisory Notes (Not Blocking)

For completeness, there are several comment-posting steps across both workflow files that lack set -euo pipefail:

sdlc-pipeline.yml:

  • Line 71: Install dependencies
  • Line 188: Post initialization comment
  • Line 278, 745, 826: Post status/completion comments
  • Line 330: Build review prompt
  • Line 535: Post loop status
  • Line 666: Post completion comment in create-pr

sdlc-hitl.yml:

  • Line 320: Post status comment
  • Line 499: Post approval comment

These are all low-risk steps (primarily posting comments), and the critical-path steps (git operations, contract updates, retry logic) all correctly include set -euo pipefail. Adding it to these remaining steps would improve consistency but is not blocking.


Summary

The blocking issue from my previous review has been properly addressed. All critical shell blocks now include set -euo pipefail. The retry logic is correct, authorization checks are in place, and the workflow is robust.

No blocking issues found. Ready for human review and merge.

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

@jwbron

jwbron commented Feb 7, 2026

Copy link
Copy Markdown
Owner

@james-in-a-box go ahead and address the advisory notes here #252 (review)

Added set -euo pipefail to the following comment-posting and
low-risk steps that were missing it:

sdlc-pipeline.yml:
- Install dependencies
- Post initialization comment
- Post status comment (implement job)
- Build review prompt
- Post loop status
- Post completion comment (create-pr, refine, plan jobs)

sdlc-hitl.yml:
- Post status comment
- Post approval comment

This improves script robustness consistency across all workflow
shell blocks.

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Added set -euo pipefail to all remaining shell steps for consistency:

sdlc-pipeline.yml:

  • Install dependencies
  • Post initialization comment
  • Post status comment (implement job)
  • Build review prompt
  • Post loop status
  • Post completion comment (create-pr, refine, plan jobs)

sdlc-hitl.yml:

  • Post status comment
  • Post approval comment

All 10 shell blocks now include set -euo pipefail for complete consistency across both workflow files.

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg finished successfully. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agent-Mode Design Re-Review: No concerns.

Changes since last review (2020cb0..24419df) add set -euo pipefail to shell script blocks — purely defensive shell safety improvements with no agent-mode design implications.

The overall design continues to align well with agent-mode principles:

  • Prompts pass lightweight metadata rather than pre-fetching large diffs
  • Agent invokes GitHub actions directly rather than outputting structured data for post-processing
  • Review prompts focus on objectives rather than rigid procedures

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg agent-mode-design completed. View run logs

@james-in-a-box james-in-a-box Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Re-Review: PR #252 — SDLC Pipeline Implementation

Previous review at commit: 3e25da90ee98abb35abcdafb8d4388c5e40c7873
Current review at commit: 24419dfebfcc1ce9cca4575bda56d9a0b9bb143c


✅ Advisory Issues Addressed

The new commit adds set -euo pipefail to all remaining shell steps for consistency, addressing the advisory notes from my previous review.

sdlc-pipeline.yml (10 locations verified):

  • Line 72: Install dependencies ✅
  • Line 190: Post initialization comment ✅
  • Line 281: Post status comment (implement job) ✅
  • Line 334: Build review prompt ✅
  • Line 540: Post loop status ✅
  • Line 672: Post completion comment (create-pr job) ✅
  • Line 752: Post completion comment (refine job) ✅
  • Line 834: Post completion comment (plan job) ✅

sdlc-hitl.yml (2 locations verified):

  • Line 321: Post status comment ✅
  • Line 501: Post approval comment ✅

Summary

All shell blocks across both workflow files now include set -euo pipefail. Combined with the fixes from previous commits:

  • ✅ Authorization checks in place
  • ✅ Retry logic with correct elif pattern
  • ✅ Concurrency controls on both workflows
  • ✅ Command injection prevention with printf
  • ✅ Path traversal prevention with numeric validation
  • ✅ Pinned Python dependencies
  • ✅ Correct audit log capturing

No blocking issues. Ready for human review and merge.

(Unable to formally approve since this PR was authored by the same bot account.)

— Authored by egg

@james-in-a-box

james-in-a-box Bot commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

egg review completed. View run logs

@jwbron
jwbron merged commit ce5d278 into main Feb 7, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant