diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..30f14fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,31 @@ +name: Bug report +description: Something does not work as documented +labels: [bug] +body: + - type: textarea + id: what + attributes: + label: What happened + description: What you did, what you expected, and what happened instead. + validations: + required: true + - type: textarea + id: repro + attributes: + label: Steps to reproduce + placeholder: | + 1. ... + 2. ... + validations: + required: true + - type: textarea + id: env + attributes: + label: Environment + description: OS, runtime versions, and the commit or release you are on. + - type: textarea + id: logs + attributes: + label: Logs + description: Relevant output. Remove tokens, hostnames and personal paths first. + render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3aa253f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Report a security vulnerability + url: https://github.com/effecet/memory-persistor/security/advisories/new + about: Please report security issues privately, not as a public issue. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..330b0c1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,19 @@ +name: Feature request +description: Suggest an improvement +labels: [enhancement] +body: + - type: textarea + id: problem + attributes: + label: Problem + description: What are you trying to do, and what gets in the way today? + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposed solution + - type: textarea + id: alternatives + attributes: + label: Alternatives considered diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 99c82d2..8fc2006 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,6 +12,11 @@ updates: open-pull-requests-limit: 5 commit-message: prefix: "[deps]" + ignore: + # dotenv 18 changed DOTENV_CONFIG_QUIET handling and breaks the stdout-transport + # guard in tests/env-loading.test.ts. Stay on 17.x until that is resolved deliberately. + - dependency-name: "dotenv" + update-types: ["version-update:semver-major"] groups: npm-dependencies: patterns: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..cd4bff8 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ +## What and why + + + +## How it was tested + + + +## Checklist + +- [ ] Tests / CI pass locally +- [ ] README and diagrams updated if behaviour or structure changed +- [ ] No secrets, hostnames or personal paths added diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12c87d0..3ed8ed4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,10 @@ name: ci -on: [push, pull_request] - +on: + push: + pull_request: + schedule: + - cron: "0 6 * * 1" # weekly, Mondays 06:00 UTC: keeps the badge honest against dependency drift + workflow_dispatch: permissions: contents: read diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000..a54e493 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,95 @@ +name: claude + +# Claude Code on this repo: +# - review: automatic review of every PR opened from a branch of this repo +# - mention: answers "@claude ..." in issues and PR comments from the owner +# +# Needs the CLAUDE_CODE_OAUTH_TOKEN repo secret (`claude setup-token`). Without +# it every job exits early and green, so CI never goes red over a missing key. +# Fork PRs and Dependabot PRs get no secrets on GitHub, so they are skipped too. + +on: + pull_request: + types: [opened, synchronize, ready_for_review] + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened] + +concurrency: + group: claude-${{ github.event.pull_request.number || github.event.issue.number }} + cancel-in-progress: true + +jobs: + review: + if: >- + github.event_name == 'pull_request' && + !github.event.pull_request.draft && + github.event.pull_request.head.repo.full_name == github.repository && + github.actor != 'dependabot[bot]' + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + pull-requests: write + id-token: write + steps: + - id: token + env: + TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + run: | + if [ -n "$TOKEN" ]; then echo "present=true" >> "$GITHUB_OUTPUT" + else echo "::notice::CLAUDE_CODE_OAUTH_TOKEN not set; skipping Claude review"; fi + - if: steps.token.outputs.present == 'true' + uses: actions/checkout@v5 + with: + fetch-depth: 1 + - if: steps.token.outputs.present == 'true' + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + prompt: | + REPO: ${{ github.repository }} + PR NUMBER: ${{ github.event.pull_request.number }} + + Review this pull request. The PR branch is checked out in the working directory. + Focus, in order: correctness bugs, security (secrets, hostnames, personal paths, + injection), contract or behaviour changes not reflected in README/diagrams, then + test gaps. Skip style nits a linter would catch. If nothing is wrong, say so briefly. + + Use `gh pr comment` for one top-level summary. + Use `mcp__github_inline_comment__create_inline_comment` (with `confirmed: true`) + for specific lines. Only post GitHub comments. + claude_args: | + --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" + + mention: + # Owner-only: on a public repo anyone can comment, and every run spends the token. + if: >- + github.event_name != 'pull_request' && + contains(github.event.comment.body || github.event.issue.body, '@claude') && + (github.event.comment.author_association || github.event.issue.author_association) == 'OWNER' + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: write + pull-requests: write + issues: write + id-token: write + steps: + - id: token + env: + TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + run: | + if [ -n "$TOKEN" ]; then echo "present=true" >> "$GITHUB_OUTPUT" + else echo "::notice::CLAUDE_CODE_OAUTH_TOKEN not set; skipping @claude"; fi + - if: steps.token.outputs.present == 'true' + uses: actions/checkout@v5 + with: + fetch-depth: 1 + - if: steps.token.outputs.present == 'true' + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..905167e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## Supported versions + +Only the latest commit on `main` is supported. Fixes are not backported. + +## Reporting a vulnerability + +Please **do not open a public issue** for security problems. + +Report privately through GitHub: open the repository's **Security** tab and +choose **Report a vulnerability** +(). + +Include what you found, how to reproduce it, and the impact you expect. You +should get a first response within a week. Once a fix ships, the advisory is +published with credit to the reporter unless you prefer to stay anonymous. + +## Scope + +This is a personal open-source project maintained on a best-effort basis. +Never commit real credentials while reproducing an issue; use placeholders.