forked from makenotion/notion-mcp-server
-
Notifications
You must be signed in to change notification settings - Fork 0
[Self-Heal] Add self-scheduling auto-repair workflow #52
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
Draft
badMade
wants to merge
1
commit into
main
Choose a base branch
from
selfheal-setup-913983608745794504
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # This file contains the current schedule for the self-healing workflow. | ||
| # It is updated automatically by scripts/compute_schedule.mjs based on telemetry. | ||
| # If you edit this manually, the automation will respect your changes until it feels a recomputation is necessary (e.g. significant PR velocity changes). | ||
| SCHEDULE: "0 0 * * *" | ||
| RATIONALE: "Initial bootstrap schedule (Daily at midnight)." | ||
| LAST_UPDATED: 1715000000000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| name: Compute Self-Heal Schedule | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "0 2 * * 0" # Runs every Sunday at 2 AM | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| actions: read | ||
|
|
||
| jobs: | ||
|
|
||
| compute-schedule: | ||
| timeout-minutes: 5 | ||
|
|
||
| runs-on: ubuntu-latest | ||
| if: github.ref == 'refs/heads/main' | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 20 | ||
| cache: "npm" | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Compute new schedule | ||
| id: compute | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| node scripts/compute_schedule.mjs > compute.log 2>&1 | ||
|
|
||
| if [ -n "$(git status --porcelain)" ]; then | ||
| echo "diff=true" >> $GITHUB_OUTPUT | ||
| git add .github/workflows/self-heal.yml .github/self-heal-schedule.yml | ||
| else | ||
| echo "diff=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Create Schedule Update PR | ||
| if: steps.compute.outputs.diff == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| RECENT_PR=$(gh pr list --label self-heal-schedule --state open --json createdAt -q '.[0].createdAt') | ||
| if [ ! -z "$RECENT_PR" ] && [ "$RECENT_PR" != "null" ]; then | ||
| echo "Recent schedule update PR exists. Skipping creation." | ||
| exit 0 | ||
| fi | ||
|
|
||
| BRANCH="selfheal-schedule-$(date +%s)" | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git checkout -b "$BRANCH" | ||
| git commit -m "Automated schedule update based on telemetry" | ||
| git push origin "$BRANCH" | ||
|
|
||
| gh pr create \ | ||
| --title "[Self-Heal Schedule] Update cadence" \ | ||
| --body "Automated PR to update the self-healing schedule based on repository telemetry." \ | ||
| --label "automation,self-heal-schedule" \ | ||
| --base main \ | ||
| --head "$BRANCH" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| name: Self-Heal Repair Pipeline | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "0 0 * * *" # AUTO-UPDATED | ||
| workflow_dispatch: | ||
| workflow_run: | ||
| workflows: ["ci"] | ||
| types: | ||
| - completed | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| actions: read | ||
|
|
||
| concurrency: | ||
| group: selfheal-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
|
|
||
| repair: | ||
| timeout-minutes: 15 | ||
|
|
||
| runs-on: ubuntu-latest | ||
| if: > | ||
| github.event_name != 'workflow_run' || | ||
| github.event.workflow_run.conclusion == 'failure' | ||
| steps: | ||
| - name: Guard against loops | ||
| if: startsWith(github.ref_name, 'selfheal-') | ||
| run: | | ||
| echo "Branch starts with 'selfheal-'. Aborting to prevent infinite loops." | ||
| exit 0 | ||
|
|
||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 20 | ||
| cache: "npm" | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Check for duplicate Self-Heal PRs | ||
| id: check-duplicate | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| # Only close stale PRs if older than 7 days | ||
| DATE=$(date -d "7 days ago" +%Y-%m-%d) | ||
| STALE_PRS=$(gh pr list --label self-heal --search "created:<$DATE" --json number -q '.[].number') | ||
| for pr in $STALE_PRS; do | ||
| gh pr close $pr --comment "Closing stale self-heal PR." | ||
| done | ||
|
|
||
| # Check for recent open PRs | ||
| RECENT_PR=$(gh pr list --label self-heal --state open --json createdAt -q '.[0].createdAt') | ||
| if [ ! -z "$RECENT_PR" ] && [ "$RECENT_PR" != "null" ]; then | ||
| echo "Recent open self-heal PR found: $RECENT_PR. Skipping execution." | ||
| echo "skip=true" >> $GITHUB_OUTPUT | ||
| exit 0 | ||
| fi | ||
| echo "skip=false" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Run pre-healthcheck | ||
| id: pre | ||
| if: steps.check-duplicate.outputs.skip != 'true' | ||
| run: node scripts/healthcheck.mjs > pre-check.log 2>&1 || echo "PRE_FAILED=true" >> $GITHUB_ENV | ||
| if [ "$PRE_FAILED" = "true" ] && [[ "${{ github.event_name }}" == "schedule" ]]; then | ||
| echo "::warning title=Self-Heal Schedule::Pre-healthcheck failed on scheduled run. System may be repeatedly failing." | ||
| fi | ||
|
|
||
| - name: Run Self-Heal Pipeline | ||
| id: repair-pipeline | ||
| if: steps.check-duplicate.outputs.skip != 'true' | ||
| run: | | ||
| node scripts/self_heal.mjs > repair.log 2>&1 | ||
| echo "REPAIR_EXIT=$?" >> $GITHUB_ENV | ||
| continue-on-error: true | ||
|
|
||
| - name: Run post-healthcheck | ||
| id: post | ||
| if: steps.check-duplicate.outputs.skip != 'true' | ||
| run: node scripts/healthcheck.mjs > post-check.log 2>&1 | ||
|
|
||
| - name: Upload Logs | ||
| if: steps.check-duplicate.outputs.skip != 'true' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: self-heal-logs | ||
| path: | | ||
| pre-check.log | ||
| repair.log | ||
| post-check.log | ||
|
|
||
| - name: Check gating conditions | ||
| id: gates | ||
| if: steps.check-duplicate.outputs.skip != 'true' && steps.post.outcome == 'success' | ||
| run: | | ||
| if [ -n "$(git status --porcelain)" ]; then | ||
| echo "diff=true" >> $GITHUB_OUTPUT | ||
|
|
||
| # Entropy scan check for secrets in diff | ||
| git add -A | ||
| if git diff --cached | grep -iE "(api[_-]?key|secret|token|password|auth|credential|access[_-]?key)=[\"']?[a-zA-Z0-9_\-]{16,}['\"]?"; then | ||
| echo "Secrets detected in diff. Aborting." | ||
| exit 1 | ||
| fi | ||
|
|
||
| # File changes NOT in forbidden files | ||
| FORBIDDEN_FILES=".github/workflows/ci.yml .env secrets/ src/**/migrations/" | ||
| for file in $FORBIDDEN_FILES; do | ||
| if git diff --cached --name-only | grep -q "$file"; then | ||
| echo "Forbidden file $file modified. Aborting." | ||
| exit 1 | ||
| fi | ||
| done | ||
|
|
||
| # We ONLY allow expected paths. Add allowed file checks here if strictly needed | ||
| else | ||
| echo "diff=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Determine PR Title | ||
| id: pr-title | ||
| if: steps.gates.outputs.diff == 'true' | ||
| run: | | ||
| TITLE="[Self-Heal Manual] Repair" | ||
| if [[ "${{ github.event_name }}" == "schedule" ]]; then | ||
| TITLE="[Self-Heal Scheduled] Drift fixes" | ||
| elif [[ "${{ github.event_name }}" == "workflow_run" ]]; then | ||
| TITLE="[Self-Heal Reactive] CI fix" | ||
| fi | ||
| echo "title=$TITLE" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Create PR | ||
| if: steps.gates.outputs.diff == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| BRANCH="selfheal-$(date +%s)" | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git checkout -b "$BRANCH" | ||
| git commit -m "Automated self-healing repair" | ||
| git push origin "$BRANCH" | ||
|
|
||
| gh pr create \ | ||
| --title "${{ steps.pr-title.outputs.title }}" \ | ||
| --body "Automated repair generated by the self-healing CI pipeline. Please review the attached artifact logs." \ | ||
| --label "automation,self-heal" \ | ||
| --base main \ | ||
| --head "$BRANCH" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # Self-Healing CI Pipeline Setup | ||
|
|
||
| This repository has been configured with an automated self-healing CI pipeline designed to address code drift, keep dependencies updated, format code, and sync types automatically. | ||
|
|
||
| ## Triggers | ||
|
|
||
| The automation runs based on three distinct triggers: | ||
| 1. **Scheduled:** Runs on an adaptive computed cadence based on telemetry. | ||
| 2. **Reactive:** Triggers automatically when the `ci` workflow fails. | ||
| 3. **Manual:** Can be triggered manually via the GitHub Actions `workflow_dispatch` UI. | ||
|
|
||
| ## The 6 Repair Steps | ||
|
|
||
| When triggered, the pipeline performs the following idempotent steps: | ||
| 1. **Clean Install:** Runs `npm ci` to ensure tooling and dependencies are correctly installed. | ||
| 2. **Format & Lint:** Runs `eslint --fix` and `prettier -w` to resolve formatting and linting errors. | ||
| 3. **Test Snapshots:** Runs `vitest run -u` to regenerate test snapshots if they've drifted. | ||
| 4. **Sync Types:** Uses `typesync` to acquire missing type stubs and updates `package.json`. | ||
| 5. **Update Dependencies:** Runs `npm update` to resolve minor or patch dependency updates safely. | ||
| 6. **Regenerate Assets:** Placeholder for any potential generic asset regeneration if applicable to this project. | ||
|
|
||
| After each step, the script checks the project's health. It will exit immediately if the state is healthy and there is a git diff, ensuring only necessary and safe changes are committed. | ||
|
|
||
| ## Self-Scheduling Logic | ||
|
|
||
| The `compute-schedule.yml` workflow runs periodically to analyze the repository's PR velocity telemetry. Based on this telemetry, it computes the most optimal schedule. | ||
|
|
||
| If the schedule changes, the workflow will create a PR to modify `.github/workflows/self-heal.yml` and `.github/self-heal-schedule.yml`. | ||
|
|
||
| ### Manual Overrides | ||
| To manually override the schedule: | ||
| 1. Modify `.github/self-heal-schedule.yml` with your desired `SCHEDULE` and `RATIONALE`. | ||
| 2. Update the timestamp in `LAST_UPDATED` (in ms since epoch). | ||
| 3. The automation will respect your change until it computes a significant velocity shift or the oscillation guard expires. | ||
|
|
||
| ## Reviewer Checklist | ||
|
|
||
| When reviewing a `selfheal-*` PR, please verify: | ||
| - [ ] No secrets or keys have been inadvertently committed. | ||
| - [ ] The `pre-check.log`, `repair.log`, and `post-check.log` artifacts provide clear explanations for the automated changes. | ||
| - [ ] Logic files (source code, tests aside from snapshots) have not been negatively impacted by the formatting/linting changes. | ||
| - [ ] Dependency updates appear intentional and safe. | ||
|
|
||
| The automation runs as `github-actions[bot]`, and any proposed changes must always undergo human review. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| export default [ | ||
| { | ||
| ignores: [ | ||
| "build/**", | ||
| "dist/**", | ||
| "coverage/**", | ||
| "bin/**", | ||
| "node_modules/**" | ||
| ] | ||
| }, | ||
| { | ||
| languageOptions: { | ||
| globals: { | ||
| console: "readonly", | ||
| process: "readonly", | ||
| setTimeout: "readonly", | ||
| clearTimeout: "readonly", | ||
| setInterval: "readonly", | ||
| clearInterval: "readonly", | ||
| __dirname: "readonly", | ||
| __filename: "readonly", | ||
| module: "readonly", | ||
| require: "readonly", | ||
| exports: "readonly", | ||
| Buffer: "readonly" | ||
| } | ||
| } | ||
| } | ||
| ]; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 current ESLint configuration does not enable any rules or extend any recommended configurations. As a result, ESLint will run with zero rules enabled, making
npx eslint --fixa no-op and rendering the linting step in the self-healing pipeline ineffective.To fix this, import
@eslint/jsand extendjs.configs.recommended(or your preferred base configuration). Note that you may also want to add@eslint/jsto yourdevDependenciesinpackage.jsonto ensure it is explicitly tracked.