-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Claude/build website builder 7p1p y #3073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
050e3e4
1e24b04
4e016fe
0f6ddeb
74cab71
5b8c595
64911e2
60ddd81
eac7ba2
79386b2
17476be
12a8978
75fbb0c
e4ddef6
cfb0f58
137d534
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,142 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: OpenHands Repair Loop | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Phase 5: Autonomous CI failure repair for Cynthia fix packs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pull_request: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| types: [labeled] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: write | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pull-requests: write | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issues: write | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| openhands-repair: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Only run when agent:repair label is added | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.event.label.name == 'agent:repair' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Checkout PR branch | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ref: ${{ github.event.pull_request.head.ref }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Safety Check - Verify Cynthia PR | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: safety | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Verify this is a Cynthia-generated PR (branch starts with 'cynthia/') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BRANCH="${{ github.event.pull_request.head.ref }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ ! "$BRANCH" =~ ^cynthia/ ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "ERROR: This workflow only runs on Cynthia-generated PRs (branch must start with 'cynthia/')" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "is_cynthia_pr=false" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "is_cynthia_pr=true" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Verified Cynthia PR: $BRANCH" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Get CI failure logs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: ci_logs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get the latest CI run status and logs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # This is a simplified version - in production, fetch actual CI logs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Fetching CI logs for PR #${{ github.event.pull_request.number }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Store logs for OpenHands context | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p /tmp/ci-logs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Build failed - type errors in src/components" > /tmp/ci-logs/build-error.log | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "CI_LOGS_PATH=/tmp/ci-logs" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+39
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incomplete implementation: CI logs are hardcoded placeholders. The CI failure logs are static dummy data, which means the OpenHands agent will receive no useful context about actual failures. Consider using the GitHub API to fetch real workflow run logs. 🔎 Example implementation using GitHub CLI - name: Get CI failure logs
id: ci_logs
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- # Get the latest CI run status and logs
- # This is a simplified version - in production, fetch actual CI logs
- echo "Fetching CI logs for PR #${{ github.event.pull_request.number }}"
-
- # Store logs for OpenHands context
mkdir -p /tmp/ci-logs
- echo "Build failed - type errors in src/components" > /tmp/ci-logs/build-error.log
+
+ # Get the latest failed workflow run for this PR's head SHA
+ HEAD_SHA="${{ github.event.pull_request.head.sha }}"
+
+ # Fetch failed check runs and their logs
+ gh api "/repos/${{ github.repository }}/commits/${HEAD_SHA}/check-runs" \
+ --jq '.check_runs[] | select(.conclusion == "failure") | {name, output}' \
+ > /tmp/ci-logs/check-runs.json 2>&1 || echo "No check runs found"
+
+ # Fetch workflow run logs if available
+ gh run list --commit "$HEAD_SHA" --status failure --json databaseId,name \
+ --jq '.[0].databaseId' | xargs -I {} gh run view {} --log-failed \
+ > /tmp/ci-logs/build-error.log 2>&1 || echo "No workflow logs found"
+
echo "CI_LOGS_PATH=/tmp/ci-logs" >> $GITHUB_OUTPUTWould you like me to open an issue to track the full implementation of CI log retrieval? 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Run OpenHands Repair Agent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: docker://ghcr.io/all-hands-ai/openhands:latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --task "Fix the CI failures in this PR. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Context: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Branch: ${{ github.event.pull_request.head.ref }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - CI logs: ${{ steps.ci_logs.outputs.CI_LOGS_PATH }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Safety rules: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Only modify files in: apps/web/client/**, packages/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - DO NOT modify: .env*, *.key, secrets/**, billing/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - DO NOT create new files unless absolutely necessary | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Commit fixes directly to this branch: ${{ github.event.pull_request.head.ref }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Use commit message: 'fix(openhands): Resolve CI failures [automated]' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. Read the CI failure logs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. Identify the root cause | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. Make minimal fixes to resolve the failures | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4. Run tests to verify the fix | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 5. Commit the changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Do NOT push to main. Only commit to the current PR branch." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+51
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Short answer — use runs.args as an array of strings (each arg is a separate item) and runs.entrypoint as a string to override ENTRYPOINT. When you consume a container action in a workflow you pass entrypoint/args under with:. Example snippets:
Notes:
Sources: GitHub Actions metadata / Dockerfile support docs. [1][2] References 🏁 Script executed: # Check if there are other references to OpenHands in the repository
rg "openhands" -i --type yaml --type yml --type md -A 3 -B 1Repository: onlook-dev/onlook Length of output: 88 🏁 Script executed: # Look for documentation or examples of how this action should be used
find . -type f \( -name "*.md" -o -name "README*" \) | head -20Repository: onlook-dev/onlook Length of output: 606 🏁 Script executed: # Search for OpenHands references in YAML files
rg "openhands" -i --type yaml -A 3 -B 1Repository: onlook-dev/onlook Length of output: 43 🏁 Script executed: # Check AGENTS.md and CLAUDE.md for documentation about OpenHands usage
head -100 AGENTS.mdRepository: onlook-dev/onlook Length of output: 4270 🌐 Web query:
💡 Result: Summary — where to find docs and how to pull the image
Useful commands
Sources 🏁 Script executed: # Look for any existing documentation about this workflow in the repository
find .github -name "*.md" -o -name "*.txt" 2>/dev/nullRepository: onlook-dev/onlook Length of output: 210 🏁 Script executed: # Search for the openhands-repair workflow to understand context
cat .github/workflows/openhands-repair.ymlRepository: onlook-dev/onlook Length of output: 5187 🌐 Web query:
💡 Result: Short answer: The Dockerized OpenHands headless entry uses the same "-t / --task" CLI flag (short form -t) to pass the task text to openhands.core.main. In Docker you append the python command and task at the end, e.g.:
Sources: 🏁 Script executed: # Check if there are any other GitHub Actions workflows that use Docker containers
# to see if there's a pattern in this repo
find .github/workflows -name "*.yml" -o -name "*.yaml" | xargs cat | grep -A 5 "docker://"Repository: onlook-dev/onlook Length of output: 318 Pin Docker image digest and fix args format for OpenHands CLI compatibility. The Reformat - name: Run OpenHands Repair Agent
- uses: docker://ghcr.io/all-hands-ai/openhands:latest
+ uses: docker://ghcr.io/all-hands-ai/openhands@sha256:<digest>
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
args: |
--task
'Fix the CI failures in this PR.
Context:
- PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}
- Branch: ${{ github.event.pull_request.head.ref }}
- CI logs: ${{ steps.ci_logs.outputs.CI_LOGS_PATH }}
Safety rules:
- Only modify files in: apps/web/client/**, packages/**
- DO NOT modify: .env*, *.key, secrets/**, billing/**
- DO NOT create new files unless absolutely necessary
- Commit fixes directly to this branch: ${{ github.event.pull_request.head.ref }}
- Use commit message: '"'"'fix(openhands): Resolve CI failures [automated]'"'"'
Steps:
1. Read the CI failure logs
2. Identify the root cause
3. Make minimal fixes to resolve the failures
4. Run tests to verify the fix
5. Commit the changes
Do NOT push to main. Only commit to the current PR branch.'
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Verify OpenHands Changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: verify | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Check if OpenHands made any commits | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COMMITS_SINCE_LABEL=$(git rev-list --count HEAD ^${{ github.event.before }}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "$COMMITS_SINCE_LABEL" -gt 0 ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "OpenHands made $COMMITS_SINCE_LABEL commit(s)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "has_changes=false" >> $GITHUB_OUTPUT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "No changes made by OpenHands" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+82
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Logic error: In a 🔎 Proposed fix: capture HEAD SHA before running OpenHandsAdd a step before running OpenHands to capture the current HEAD: + - name: Capture HEAD before repair
+ id: pre_repair
+ run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
+
- name: Run OpenHands Repair Agent
uses: docker://ghcr.io/all-hands-ai/openhands:latest
# ... existing config ...
- name: Verify OpenHands Changes
id: verify
run: |
- # Check if OpenHands made any commits
- COMMITS_SINCE_LABEL=$(git rev-list --count HEAD ^${{ github.event.before }})
-
- if [ "$COMMITS_SINCE_LABEL" -gt 0 ]; then
+ # Check if OpenHands made any commits since we captured the SHA
+ CURRENT_SHA=$(git rev-parse HEAD)
+ PRE_REPAIR_SHA="${{ steps.pre_repair.outputs.sha }}"
+
+ if [ "$CURRENT_SHA" != "$PRE_REPAIR_SHA" ]; then
+ COMMITS_COUNT=$(git rev-list --count HEAD ^"$PRE_REPAIR_SHA")
echo "has_changes=true" >> $GITHUB_OUTPUT
- echo "OpenHands made $COMMITS_SINCE_LABEL commit(s)"
+ echo "OpenHands made $COMMITS_COUNT commit(s)"
else
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes made by OpenHands"
fi
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Push repairs to PR branch | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.verify.outputs.has_changes == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git config user.name "Cynthia OpenHands Bot" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git config user.email "openhands@cynthia.onlook.dev" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Push to PR branch only (never main) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BRANCH="${{ github.event.pull_request.head.ref }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git push origin "$BRANCH" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Repairs pushed to branch: $BRANCH" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+96
to
+106
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security: Same script injection vulnerability in push step. The branch name is again directly interpolated into the shell script. 🔎 Proposed fix - name: Push repairs to PR branch
if: steps.verify.outputs.has_changes == 'true'
+ env:
+ BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
git config user.name "Cynthia OpenHands Bot"
git config user.email "openhands@cynthia.onlook.dev"
# Push to PR branch only (never main)
- BRANCH="${{ github.event.pull_request.head.ref }}"
git push origin "$BRANCH"
echo "Repairs pushed to branch: $BRANCH"🧰 Tools🪛 actionlint (1.7.9)98-98: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details (expression) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Comment on PR | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.verify.outputs.has_changes == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/github-script@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const comment = `🤖 **OpenHands Repair Agent** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| I've attempted to fix the CI failures in this PR. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Changes made:** ${context.payload.pull_request.head.sha.substring(0, 7)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Branch:** \`${context.payload.pull_request.head.ref}\` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CI checks will re-run automatically. If failures persist, please review the changes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *Automated by [Cynthia](https://onlook.dev) OpenHands integration*`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| github.rest.issues.createComment({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner: context.repo.owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo: context.repo.repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: context.payload.pull_request.number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: comment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Remove repair label | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: always() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/github-script@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| script: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| github.rest.issues.removeLabel({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner: context.repo.owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repo: context.repo.repo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| issue_number: context.payload.pull_request.number, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'agent:repair' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+108
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing The 🔎 Proposed fix - name: Comment on PR
if: steps.verify.outputs.has_changes == 'true'
uses: actions/github-script@v7
with:
script: |
const comment = `🤖 **OpenHands Repair Agent**
I've attempted to fix the CI failures in this PR.
**Changes made:** ${context.payload.pull_request.head.sha.substring(0, 7)}
**Branch:** \`${context.payload.pull_request.head.ref}\`
CI checks will re-run automatically. If failures persist, please review the changes.
---
*Automated by [Cynthia](https://onlook.dev) OpenHands integration*`;
- github.rest.issues.createComment({
+ await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: comment
});
- name: Remove repair label
if: always()
uses: actions/github-script@v7
with:
script: |
- github.rest.issues.removeLabel({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: context.payload.pull_request.number,
- name: 'agent:repair'
- });
+ try {
+ await github.rest.issues.removeLabel({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.payload.pull_request.number,
+ name: 'agent:repair'
+ });
+ } catch (error) {
+ if (error.status !== 404) {
+ throw error;
+ }
+ console.log('Label already removed');
+ }🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| -- PHASE 3: Add Audit Fields to Build Sessions | ||
| -- Created: 2025-12-19 | ||
| -- Purpose: Wire build sessions to real Cynthia audits | ||
|
|
||
| -- ============================================================ | ||
| -- ENUMS | ||
| -- ============================================================ | ||
|
|
||
| -- Build session audit status enum | ||
| CREATE TYPE build_session_audit_status AS ENUM ( | ||
| 'pending', | ||
| 'running', | ||
| 'completed', | ||
| 'failed' | ||
| ); | ||
|
|
||
| -- ============================================================ | ||
| -- ALTER TABLES | ||
| -- ============================================================ | ||
|
|
||
| -- Add audit fields to build_sessions | ||
| ALTER TABLE build_sessions | ||
| ADD COLUMN audit_id UUID REFERENCES cynthia_audits(id) ON DELETE SET NULL ON UPDATE CASCADE, | ||
| ADD COLUMN audit_status build_session_audit_status DEFAULT 'pending'; | ||
|
Comment on lines
+21
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This migration adds Useful? React with 👍 / 👎. |
||
|
|
||
| -- ============================================================ | ||
| -- INDEXES | ||
| -- ============================================================ | ||
|
|
||
| -- Index on build_sessions.audit_id for audit lookups | ||
| CREATE INDEX idx_build_sessions_audit_id ON build_sessions(audit_id); | ||
|
|
||
| -- Index on build_sessions.audit_status for filtering by status | ||
| CREATE INDEX idx_build_sessions_audit_status ON build_sessions(audit_status); | ||
|
|
||
| -- ============================================================ | ||
| -- COMMENTS | ||
| -- ============================================================ | ||
|
|
||
| COMMENT ON COLUMN build_sessions.audit_id IS 'Phase 3: Links to real Cynthia audit (nullable until audit completes)'; | ||
| COMMENT ON COLUMN build_sessions.audit_status IS 'Phase 3: Tracks audit processing state (pending → running → completed/failed)'; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,194 @@ | ||||||||||||||||||||||||||||||
| -- PHASE 2: Build Sessions & Preview Links | ||||||||||||||||||||||||||||||
| -- Created: 2025-12-19 | ||||||||||||||||||||||||||||||
| -- Purpose: Add tables for "Build My Site" viral wedge functionality | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
| -- ENUMS | ||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Build session status enum | ||||||||||||||||||||||||||||||
| CREATE TYPE build_session_status AS ENUM ( | ||||||||||||||||||||||||||||||
| 'created', | ||||||||||||||||||||||||||||||
| 'previewed', | ||||||||||||||||||||||||||||||
| 'locked', | ||||||||||||||||||||||||||||||
| 'converted' | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Build session input type enum | ||||||||||||||||||||||||||||||
| CREATE TYPE build_session_input_type AS ENUM ( | ||||||||||||||||||||||||||||||
| 'idea', | ||||||||||||||||||||||||||||||
| 'url' | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
| -- TABLES | ||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Build sessions table | ||||||||||||||||||||||||||||||
| -- Stores each "Build My Site" session (anonymous or authenticated) | ||||||||||||||||||||||||||||||
| CREATE TABLE IF NOT EXISTS build_sessions ( | ||||||||||||||||||||||||||||||
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||||||||||||||||||||||||||||
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | ||||||||||||||||||||||||||||||
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Session data | ||||||||||||||||||||||||||||||
| language TEXT NOT NULL DEFAULT 'en', -- 'en' | 'es' | ||||||||||||||||||||||||||||||
| input_type build_session_input_type NOT NULL, | ||||||||||||||||||||||||||||||
| input_value TEXT NOT NULL, | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Audit results (static for Phase 2, real in Phase 3) | ||||||||||||||||||||||||||||||
| teaser_score INTEGER, | ||||||||||||||||||||||||||||||
| teaser_summary JSONB, | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Status tracking | ||||||||||||||||||||||||||||||
| status build_session_status NOT NULL DEFAULT 'created', | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- User relationship (nullable - anonymous sessions allowed) | ||||||||||||||||||||||||||||||
| user_id UUID REFERENCES auth.users(id) ON DELETE SET NULL ON UPDATE CASCADE | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Preview links table | ||||||||||||||||||||||||||||||
| -- Public shareable links for build sessions | ||||||||||||||||||||||||||||||
| CREATE TABLE IF NOT EXISTS preview_links ( | ||||||||||||||||||||||||||||||
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||||||||||||||||||||||||||||
| created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Build session relationship | ||||||||||||||||||||||||||||||
| build_session_id UUID NOT NULL REFERENCES build_sessions(id) ON DELETE CASCADE ON UPDATE CASCADE, | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Public slug for sharing (unguessable) | ||||||||||||||||||||||||||||||
| slug TEXT NOT NULL UNIQUE, | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Optional expiration | ||||||||||||||||||||||||||||||
| expires_at TIMESTAMPTZ | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
| -- INDEXES | ||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Index on preview_links.slug for fast lookup | ||||||||||||||||||||||||||||||
| CREATE INDEX idx_preview_links_slug ON preview_links(slug); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Index on build_sessions.user_id for user session queries | ||||||||||||||||||||||||||||||
| CREATE INDEX idx_build_sessions_user_id ON build_sessions(user_id); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Index on build_sessions.status for status filtering | ||||||||||||||||||||||||||||||
| CREATE INDEX idx_build_sessions_status ON build_sessions(status); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
| -- ROW LEVEL SECURITY (RLS) POLICIES | ||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- Enable RLS on both tables | ||||||||||||||||||||||||||||||
| ALTER TABLE build_sessions ENABLE ROW LEVEL SECURITY; | ||||||||||||||||||||||||||||||
| ALTER TABLE preview_links ENABLE ROW LEVEL SECURITY; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
| -- BUILD_SESSIONS POLICIES | ||||||||||||||||||||||||||||||
| -- ============================================================ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- RLS Policy: Public insert allowed (anonymous users can create sessions) | ||||||||||||||||||||||||||||||
| -- Rationale: "No signup to start" - anyone can create a build session | ||||||||||||||||||||||||||||||
| DROP POLICY IF EXISTS "build_sessions_insert_policy" ON build_sessions; | ||||||||||||||||||||||||||||||
| CREATE POLICY "build_sessions_insert_policy" ON build_sessions | ||||||||||||||||||||||||||||||
| FOR INSERT | ||||||||||||||||||||||||||||||
| TO anon, authenticated | ||||||||||||||||||||||||||||||
| WITH CHECK (true); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- RLS Policy: Public select DENIED (no public listing of sessions) | ||||||||||||||||||||||||||||||
| -- Rationale: Sessions are private by default, only accessible via preview link | ||||||||||||||||||||||||||||||
| DROP POLICY IF EXISTS "build_sessions_select_anon_policy" ON build_sessions; | ||||||||||||||||||||||||||||||
| CREATE POLICY "build_sessions_select_anon_policy" ON build_sessions | ||||||||||||||||||||||||||||||
| FOR SELECT | ||||||||||||||||||||||||||||||
| TO anon | ||||||||||||||||||||||||||||||
| USING (false); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- RLS Policy: Owner select allowed (users can see their own sessions) | ||||||||||||||||||||||||||||||
| -- Rationale: Authenticated users can view sessions they created | ||||||||||||||||||||||||||||||
| DROP POLICY IF EXISTS "build_sessions_select_owner_policy" ON build_sessions; | ||||||||||||||||||||||||||||||
| CREATE POLICY "build_sessions_select_owner_policy" ON build_sessions | ||||||||||||||||||||||||||||||
| FOR SELECT | ||||||||||||||||||||||||||||||
| TO authenticated | ||||||||||||||||||||||||||||||
| USING (user_id = auth.uid()); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| -- RLS Policy: Owner update allowed (users can update their own sessions) | ||||||||||||||||||||||||||||||
| -- Rationale: Users can change status or claim anonymous sessions | ||||||||||||||||||||||||||||||
| DROP POLICY IF EXISTS "build_sessions_update_owner_policy" ON build_sessions; | ||||||||||||||||||||||||||||||
| CREATE POLICY "build_sessions_update_owner_policy" ON build_sessions | ||||||||||||||||||||||||||||||
| FOR UPDATE | ||||||||||||||||||||||||||||||
| TO authenticated | ||||||||||||||||||||||||||||||
| USING (user_id = auth.uid() OR user_id IS NULL) | ||||||||||||||||||||||||||||||
|
Comment on lines
+116
to
+121
|
||||||||||||||||||||||||||||||
| -- Rationale: Users can change status or claim anonymous sessions | |
| DROP POLICY IF EXISTS "build_sessions_update_owner_policy" ON build_sessions; | |
| CREATE POLICY "build_sessions_update_owner_policy" ON build_sessions | |
| FOR UPDATE | |
| TO authenticated | |
| USING (user_id = auth.uid() OR user_id IS NULL) | |
| -- Rationale: Authenticated users can only update sessions they own; associating | |
| -- anonymous sessions with a user must be done via trusted backend code | |
| DROP POLICY IF EXISTS "build_sessions_update_owner_policy" ON build_sessions; | |
| CREATE POLICY "build_sessions_update_owner_policy" ON build_sessions | |
| FOR UPDATE | |
| TO authenticated | |
| USING (user_id = auth.uid()) |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The preview_links_select_by_slug_policy grants SELECT on all preview_links rows to both anon and authenticated roles with USING (true), which lets anyone holding the public Supabase anon key enumerate every preview slug and associated build_session_id. This breaks the intended "unguessable slug, no enumeration" security model and allows an attacker to list all share links and then fetch each preview (and, in combination with the build session update policy, potentially take over those sessions). Restrict SELECT so that public roles can only read a single row by a provided slug through a tightly scoped backend endpoint or RPC (and not via unrestricted table SELECT), and ensure expired links and any sensitive fields are filtered server-side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preview_links_insert_policy blocks anonymous session creation flow.
The policy only allows authenticated users to insert preview links, but the application flow (per build-session.ts) creates preview links for anonymous users. This will cause inserts to fail for anonymous sessions unless the insert bypasses RLS (e.g., using a service role).
🔎 Potential fixes
Option 1: Allow anon to insert (if acceptable):
CREATE POLICY "preview_links_insert_policy" ON preview_links
FOR INSERT
-TO authenticated
+TO anon, authenticated
WITH CHECK (true);Option 2: Ensure the tRPC router uses a service role connection that bypasses RLS for anonymous session creation. Verify this is the intended design.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| -- RLS Policy: No public insert (only server/authenticated can create) | |
| -- Rationale: Prevent spam, only app can generate preview links | |
| DROP POLICY IF EXISTS "preview_links_insert_policy" ON preview_links; | |
| CREATE POLICY "preview_links_insert_policy" ON preview_links | |
| FOR INSERT | |
| TO authenticated | |
| WITH CHECK (true); | |
| -- RLS Policy: No public insert (only server/authenticated can create) | |
| -- Rationale: Prevent spam, only app can generate preview links | |
| DROP POLICY IF EXISTS "preview_links_insert_policy" ON preview_links; | |
| CREATE POLICY "preview_links_insert_policy" ON preview_links | |
| FOR INSERT | |
| TO anon, authenticated | |
| WITH CHECK (true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security: Script injection vulnerability via untrusted branch name.
The
github.event.pull_request.head.refis directly interpolated into the shell script, which allows script injection attacks. An attacker could create a branch name containing shell metacharacters to execute arbitrary commands.🔎 Proposed fix using environment variable
- name: Safety Check - Verify Cynthia PR id: safety + env: + BRANCH: ${{ github.event.pull_request.head.ref }} run: | # Verify this is a Cynthia-generated PR (branch starts with 'cynthia/') - BRANCH="${{ github.event.pull_request.head.ref }}" if [[ ! "$BRANCH" =~ ^cynthia/ ]]; then echo "ERROR: This workflow only runs on Cynthia-generated PRs (branch must start with 'cynthia/')" echo "is_cynthia_pr=false" >> $GITHUB_OUTPUT exit 1 fi echo "is_cynthia_pr=true" >> $GITHUB_OUTPUT echo "Verified Cynthia PR: $BRANCH"🧰 Tools
🪛 actionlint (1.7.9)
28-28: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details
(expression)
🤖 Prompt for AI Agents