From 47dc719416d46f53f8263ca825c135232f161575 Mon Sep 17 00:00:00 2001 From: Rat Date: Sun, 16 Aug 2026 13:33:15 +0800 Subject: [PATCH] chore: harden repository maintenance and releases --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/bug_report.yml | 73 +++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 + .github/ISSUE_TEMPLATE/feature_request.yml | 34 +++++ .github/dependabot.yml | 27 ++++ .github/pull_request_template.md | 19 +++ .github/scripts/extract-release-notes/main.go | 70 +++++++++ .../extract-release-notes/main_test.go | 43 ++++++ .github/workflows/build.yml | 139 +++++++++++++++--- CHANGELOG.md | 65 ++++++++ CONTRIBUTING.md | 44 ++++++ README.md | 12 ++ SECURITY.md | 24 +++ 13 files changed, 532 insertions(+), 24 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/scripts/extract-release-notes/main.go create mode 100644 .github/scripts/extract-release-notes/main_test.go create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..3d60240 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Rat0323 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..6a60eb7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,73 @@ +name: Bug report +description: Report reproducible plugin behavior that is not security-sensitive. +title: "[Bug] " +labels: + - bug +body: + - type: markdown + attributes: + value: >- + Do not include credentials, raw request bodies, encrypted reasoning, or + conversation text. Report security issues privately through the Security + tab. + - type: input + id: plugin-version + attributes: + label: Plugin version + placeholder: v0.2.0 + validations: + required: true + - type: input + id: cpa-version + attributes: + label: CLIProxyAPI version + placeholder: 7.2.130 + validations: + required: true + - type: input + id: platform + attributes: + label: Platform + description: Operating system and architecture. + placeholder: Windows 11 amd64 + validations: + required: true + - type: dropdown + id: installation + attributes: + label: Installation method + options: + - CPA plugin store + - Manual release archive + - Local development build + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + description: Describe the observed and expected behavior. + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction steps + description: Provide the smallest repeatable sequence. + validations: + required: true + - type: textarea + id: diagnostics + attributes: + label: Sanitized diagnostics + description: Include only privacy-safe plugin records with secrets removed. + render: text + - type: checkboxes + id: confirmation + attributes: + label: Confirmation + options: + - label: I removed credentials, raw bodies, encrypted content, and conversation text. + required: true + - label: This report is not a private security vulnerability. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..98cb8c7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Security vulnerability + url: https://github.com/Rat0323/cpa-plugin-codex-switch-safe/security/advisories/new + about: Report security-sensitive findings privately. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..5de7607 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,34 @@ +name: Feature request +description: Propose a focused improvement to plugin behavior or diagnostics. +title: "[Feature] " +labels: + - enhancement +body: + - type: textarea + id: problem + attributes: + label: Problem + description: Describe the concrete CPA or Codex workflow problem. + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposed behavior + description: Explain the expected plugin behavior and configuration impact. + validations: + required: true + - type: textarea + id: safety + attributes: + label: Safety considerations + description: Note effects on encrypted state, routing, privacy, or availability. + validations: + required: true + - type: checkboxes + id: scope + attributes: + label: Scope confirmation + options: + - label: This request is specific to CPA plugin behavior or Codex route safety. + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..805f90b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +version: 2 +updates: + - package-ecosystem: gomod + directory: / + schedule: + interval: monthly + groups: + go-dependencies: + patterns: + - "*" + labels: + - dependencies + - go + open-pull-requests-limit: 5 + + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + groups: + github-actions: + patterns: + - "*" + labels: + - dependencies + - github-actions + open-pull-requests-limit: 5 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..70c864c --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ +# Pull Request + +## Summary + +Describe what changes and why. + +## Safety impact + +Describe any effect on route identity, encrypted reasoning, compaction, retries, +failover, diagnostics, or request sanitization. Write `None` when not applicable. + +## Validation + +- [ ] `go test ./...` +- [ ] `go test -race ./...` +- [ ] `go vet ./...` +- [ ] User-facing changes are documented in `CHANGELOG.md` or are not applicable +- [ ] No credentials, request bodies, encrypted content, or conversation text + are included diff --git a/.github/scripts/extract-release-notes/main.go b/.github/scripts/extract-release-notes/main.go new file mode 100644 index 0000000..adf018c --- /dev/null +++ b/.github/scripts/extract-release-notes/main.go @@ -0,0 +1,70 @@ +package main + +import ( + "flag" + "fmt" + "os" + "regexp" + "strings" +) + +var releaseVersionPattern = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`) + +func main() { + changelogPath := flag.String("changelog", "CHANGELOG.md", "path to the changelog") + version := flag.String("version", "", "release version without a leading v") + outputPath := flag.String("output", "release-notes.md", "path for extracted notes") + flag.Parse() + + if !releaseVersionPattern.MatchString(*version) { + fail("version must use dotted numeric form without a leading v") + } + + content, errRead := os.ReadFile(*changelogPath) + if errRead != nil { + fail("read changelog: %v", errRead) + } + + notes, errExtract := extractReleaseNotes(string(content), *version) + if errExtract != nil { + fail("extract release notes: %v", errExtract) + } + if errWrite := os.WriteFile(*outputPath, []byte(notes+"\n"), 0o644); errWrite != nil { + fail("write release notes: %v", errWrite) + } +} + +func extractReleaseNotes(changelog, version string) (string, error) { + lines := strings.Split(strings.ReplaceAll(changelog, "\r\n", "\n"), "\n") + headerPrefix := "## [" + version + "]" + start := -1 + + for index, line := range lines { + if strings.HasPrefix(line, headerPrefix) { + start = index + 1 + break + } + } + if start == -1 { + return "", fmt.Errorf("missing %s section", headerPrefix) + } + + end := len(lines) + for index := start; index < len(lines); index++ { + if strings.HasPrefix(lines[index], "## [") { + end = index + break + } + } + + notes := strings.TrimSpace(strings.Join(lines[start:end], "\n")) + if notes == "" { + return "", fmt.Errorf("%s section is empty", headerPrefix) + } + return notes, nil +} + +func fail(format string, args ...any) { + fmt.Fprintf(os.Stderr, format+"\n", args...) + os.Exit(1) +} diff --git a/.github/scripts/extract-release-notes/main_test.go b/.github/scripts/extract-release-notes/main_test.go new file mode 100644 index 0000000..8f4a32c --- /dev/null +++ b/.github/scripts/extract-release-notes/main_test.go @@ -0,0 +1,43 @@ +package main + +import ( + "strings" + "testing" +) + +func TestExtractReleaseNotes(t *testing.T) { + changelog := "# Changelog\r\n\r\n## [Unreleased]\r\n\r\n## [1.2.3] - 2026-08-16\r\n\r\n### Added\r\n\r\n- Safe release notes.\r\n\r\n## [1.2.2] - 2026-08-15\r\n\r\n- Older notes.\r\n" + + notes, errExtract := extractReleaseNotes(changelog, "1.2.3") + if errExtract != nil { + t.Fatalf("extract release notes: %v", errExtract) + } + if strings.Contains(notes, "Older notes") { + t.Fatalf("notes crossed into the previous release: %q", notes) + } + if !strings.Contains(notes, "Safe release notes") { + t.Fatalf("notes omitted current release content: %q", notes) + } +} + +func TestExtractReleaseNotesRejectsMissingOrEmptySection(t *testing.T) { + for name, testCase := range map[string]struct { + changelog string + version string + }{ + "missing": { + changelog: "# Changelog\n\n## [1.0.0]\n\n- Notes.\n", + version: "1.2.4", + }, + "empty": { + changelog: "# Changelog\n\n## [1.2.3]\n\n## [1.2.2]\n\n- Notes.\n", + version: "1.2.3", + }, + } { + t.Run(name, func(t *testing.T) { + if _, errExtract := extractReleaseNotes(testCase.changelog, testCase.version); errExtract == nil { + t.Fatal("expected extraction to fail") + } + }) + } +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8c832e..0a37e24 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,11 +4,15 @@ on: pull_request: push: tags: - - 'v*' + - "v*" workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + permissions: - contents: write + contents: read env: PLUGIN_ID: codex-switch-safe @@ -17,13 +21,19 @@ jobs: test: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 - - uses: actions/setup-go@v6 + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version-file: go.mod cache: true - - run: go test ./... - - run: go vet ./... + - name: Test + run: | + go test ./... + go test ./.github/scripts/extract-release-notes + - name: Race detector + run: go test -race ./... + - name: Vet + run: go vet ./... build: needs: test @@ -56,25 +66,38 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v5 - - uses: actions/setup-go@v6 + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version-file: go.mod cache: true - name: Resolve release metadata run: | - if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then VERSION="${GITHUB_REF_NAME#v}"; else VERSION="0.0.0-dev"; fi + if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then + VERSION="${GITHUB_REF_NAME#v}" + else + VERSION="0.0.0-dev" + fi echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" echo "LIB_NAME=${PLUGIN_ID}.${{ matrix.ext }}" >> "${GITHUB_ENV}" echo "ARCHIVE_NAME=${PLUGIN_ID}_${VERSION}_${{ matrix.goos }}_${{ matrix.goarch }}.zip" >> "${GITHUB_ENV}" - name: Build shared library run: | mkdir -p dist - CGO_ENABLED=1 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -trimpath -buildmode=c-shared -ldflags "-s -w -X main.pluginVersion=${VERSION}" -o "dist/${LIB_NAME}" . + CGO_ENABLED=1 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \ + go build -trimpath -buildmode=c-shared \ + -ldflags "-s -w -X main.pluginVersion=${VERSION}" \ + -o "dist/${LIB_NAME}" . rm -f "dist/${PLUGIN_ID}.h" - name: Package - run: go run ./.github/scripts/package-release.go -library "dist/${LIB_NAME}" -archive "${ARCHIVE_NAME}" -checksum "${ARCHIVE_NAME}.sha256" - - uses: actions/upload-artifact@v7 + run: >- + go run ./.github/scripts/package-release.go + -library "dist/${LIB_NAME}" + -archive "${ARCHIVE_NAME}" + -checksum "${ARCHIVE_NAME}.sha256" + - name: Upload release artifact + if: startsWith(github.ref, 'refs/tags/v') + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: ${{ env.ARCHIVE_NAME }} path: | @@ -85,19 +108,23 @@ jobs: needs: test runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 - - uses: actions/setup-go@v6 + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 with: go-version-file: go.mod cache: true - name: Resolve release metadata id: release run: | - if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then VERSION="${GITHUB_REF_NAME#v}"; else VERSION="0.0.0-dev"; fi + if [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then + VERSION="${GITHUB_REF_NAME#v}" + else + VERSION="0.0.0-dev" + fi echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" echo "ARCHIVE_NAME=${PLUGIN_ID}_${VERSION}_windows_arm64.zip" >> "${GITHUB_ENV}" - - uses: go-cross/cgo-actions@v1 + - uses: go-cross/cgo-actions@d0b8f2f2d67923ce9a42d92a7ef0ed1ebd905f0a # v1 env: GOFLAGS: -trimpath -buildmode=c-shared with: @@ -111,27 +138,91 @@ jobs: - name: Package run: | rm -f go-cross-bin.h "dist/windows-arm64/${PLUGIN_ID}.h" - go run ./.github/scripts/package-release.go -library "dist/windows-arm64/${PLUGIN_ID}.dll" -archive "${ARCHIVE_NAME}" -checksum "${ARCHIVE_NAME}.sha256" - - uses: actions/upload-artifact@v7 + go run ./.github/scripts/package-release.go \ + -library "dist/windows-arm64/${PLUGIN_ID}.dll" \ + -archive "${ARCHIVE_NAME}" \ + -checksum "${ARCHIVE_NAME}.sha256" + - name: Upload release artifact + if: startsWith(github.ref, 'refs/tags/v') + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: ${{ env.ARCHIVE_NAME }} path: | ${{ env.ARCHIVE_NAME }} ${{ env.ARCHIVE_NAME }}.sha256 + ci: + if: always() + needs: [test, build, build-windows-arm64] + runs-on: ubuntu-24.04 + steps: + - name: Verify required jobs + env: + TEST_RESULT: ${{ needs.test.result }} + BUILD_RESULT: ${{ needs.build.result }} + WINDOWS_ARM64_RESULT: ${{ needs.build-windows-arm64.result }} + run: | + test "${TEST_RESULT}" = "success" + test "${BUILD_RESULT}" = "success" + test "${WINDOWS_ARM64_RESULT}" = "success" + release: if: startsWith(github.ref, 'refs/tags/v') - needs: [build, build-windows-arm64] + needs: ci runs-on: ubuntu-24.04 + permissions: + contents: write steps: - - uses: actions/checkout@v5 - - uses: actions/download-artifact@v8 + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 + with: + go-version-file: go.mod + cache: true + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: path: dist merge-multiple: true - - name: Publish release + - name: Prepare and verify release + run: | + VERSION="${GITHUB_REF_NAME#v}" + echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" + + grep -Fqx "var pluginVersion = \"${VERSION}\"" main.go + grep -Fqx "VERSION ?= ${VERSION}" Makefile + jq -e --arg version "${VERSION}" \ + '.version == $version' marketplace/registry-entry.json >/dev/null + + go run ./.github/scripts/extract-release-notes \ + -changelog CHANGELOG.md \ + -version "${VERSION}" \ + -output dist/release-notes.md + + test "$(find dist -maxdepth 1 -type f -name '*.zip' | wc -l)" -eq 6 + test "$(find dist -maxdepth 1 -type f -name '*.sha256' | wc -l)" -eq 6 + sort dist/*.sha256 > dist/checksums.txt + (cd dist && sha256sum -c checksums.txt) + - name: Create draft release env: GH_TOKEN: ${{ github.token }} run: | - sort dist/*.sha256 > dist/checksums.txt - gh release create "${GITHUB_REF_NAME}" dist/*.zip dist/checksums.txt --verify-tag --title "${GITHUB_REF_NAME}" --generate-notes + gh release create "${GITHUB_REF_NAME}" \ + dist/*.zip dist/checksums.txt \ + --draft \ + --verify-tag \ + --title "Codex Switch Safe ${GITHUB_REF_NAME}" \ + --notes-file dist/release-notes.md + - name: Verify and publish release + env: + GH_TOKEN: ${{ github.token }} + run: | + { + find dist -maxdepth 1 -type f -name '*.zip' -printf '%f\n' + echo checksums.txt + } | sort > dist/expected-assets.txt + + gh release view "${GITHUB_REF_NAME}" \ + --json assets \ + --jq '.assets[].name' | sort > dist/actual-assets.txt + + diff -u dist/expected-assets.txt dist/actual-assets.txt + gh release edit "${GITHUB_REF_NAME}" --draft=false --latest diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8e8a358 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,65 @@ +# Changelog + +All notable user-facing changes to Codex Switch Safe are documented here. +The project follows semantic versioning, and release automation publishes the +matching version section verbatim. + +## [Unreleased] + +## [0.2.0] - 2026-08-15 + +### Highlights + +- Added privacy-safe diagnostics for route decisions, protection actions, and + request lifecycle outcomes. +- Added route-scoped retired-item barriers so a rejected failover candidate + does not retire valid state from the original route. +- Made route tracking retry-aware and lifecycle-aware. Failed, rejected, + canceled, and expired attempts do not advance the committed route. +- Preserved encrypted reasoning on the same selected CPA credential/model route + while stripping only unsafe top-level route-bound state during switching. +- Expanded regression coverage for encrypted reasoning, compaction, retries, + failover, concurrency, and diagnostics. + +### Behavior + +- Same-route encrypted reasoning passes through unchanged. +- Unknown, changed, expired, or ambiguous routes are handled conservatively so + foreign encrypted state is not sent to a new upstream. +- Unsafe compaction returns HTTP 409 by default. Setting + `compaction_policy: strip` continues without unsafe compaction context. +- A successful lifecycle outcome is required before a route and its + route-bound item fingerprints are committed. +- Diagnostics default to `actions`; `debug` adds safe pass-through decisions, + and `off` disables plugin diagnostics. + +### Upgrade notes + +- Requires CLIProxyAPI `7.2.130` or newer. +- Existing plugin configuration remains compatible. +- Release assets cover Linux, macOS, and Windows on `amd64` and `arm64`. + +## [0.1.1] - 2026-08-14 + +### Fixed + +- Committed selected credential routes only after successful upstream requests. +- Prevented failed failover candidates from retiring valid reasoning items. +- Added process-local keyed fingerprints for top-level route-bound items. +- Improved stable session identity detection and bounded-state failure handling. +- Completed live dual-provider switching validation and six-platform builds. + +### Compatibility + +- Requires CLIProxyAPI `7.2.130` or newer. +- Users of `v0.1.0` should upgrade to this release. + +## [0.1.0] - 2026-08-14 + +Initial release. This version is deprecated because retry and session edge cases +were corrected in `v0.1.1`. + +[Unreleased]: https://github.com/Rat0323/cpa-plugin-codex-switch-safe/compare/v0.2.0...HEAD +[0.2.0]: https://github.com/Rat0323/cpa-plugin-codex-switch-safe/releases/tag/v0.2.0 +[0.1.1]: https://github.com/Rat0323/cpa-plugin-codex-switch-safe/releases/tag/v0.1.1 +[0.1.0]: https://github.com/Rat0323/cpa-plugin-codex-switch-safe/releases/tag/v0.1.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..af5232a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +# Contributing + +Thanks for helping improve Codex Switch Safe. + +## Before opening a change + +- Use an issue for reproducible bugs or behavior proposals. +- Use private vulnerability reporting for security-sensitive findings. +- Keep changes focused on Codex route-bound state safety and CPA plugin + integration. +- Never include credentials, raw request bodies, encrypted reasoning, or user + conversation content in tests, issues, commits, or logs. + +## Development checks + +```powershell +$go = 'C:\Program Files\Go\bin\go.exe' +& $go test ./... +& $go test -race ./... +& $go vet ./... +``` + +Native shared-library builds require a C compiler. Pull requests run tests and +all six supported platform builds in GitHub Actions. + +## Pull requests + +- Explain the behavior change and its safety implications. +- Add focused regression tests for state, retry, failover, or sanitization + changes. +- Update README configuration or diagnostics documentation when behavior changes. +- Add user-facing changes under `[Unreleased]` in `CHANGELOG.md`. +- Keep version bumps in a dedicated release-preparation pull request. + +## Releases + +A release-preparation pull request moves relevant changelog entries from +`[Unreleased]` into a dated version section and synchronizes the version in +`main.go`, `Makefile`, and `marketplace/registry-entry.json`. + +After that pull request is merged and verified, create and push the matching +`v` tag. The release workflow validates metadata and checksums, creates +a draft release, uploads all platform assets, verifies the asset list, and then +publishes it. diff --git a/README.md b/README.md index 53b1bf2..fddca83 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,18 @@ Native builds require a C compiler because CPA loads the Go shared library through the native ABI. CI tests the plugin and publishes Linux, macOS, and Windows release assets from version tags. +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for development checks, pull request +expectations, and the release process. User-facing changes are tracked in +[CHANGELOG.md](CHANGELOG.md). + +## Security + +Report security-sensitive findings through GitHub private vulnerability +reporting instead of a public issue. See [SECURITY.md](SECURITY.md) for supported +versions and disclosure guidance. + ## License MIT. See [LICENSE](LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..3cd3f0b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,24 @@ +# Security Policy + +## Supported versions + +Only the latest release line receives security fixes. + +| Version | Supported | +| --- | --- | +| `0.2.x` | Yes | +| `< 0.2` | No | + +## Reporting a vulnerability + +Use [GitHub private vulnerability reporting](https://github.com/Rat0323/cpa-plugin-codex-switch-safe/security/advisories/new) +for security-sensitive findings. + +Do not open a public issue containing credentials, authorization headers, raw +CPA request bodies, session identifiers, encrypted reasoning content, or user +conversation text. + +Include the affected plugin and CPA versions, operating system and architecture, +reproduction steps, expected impact, and sanitized logs where possible. You can +expect an initial acknowledgment within seven days. Fix timing depends on the +severity and reproducibility of the report.