Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @Rat0323
73 changes: 73 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -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.
34 changes: 34 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -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
70 changes: 70 additions & 0 deletions .github/scripts/extract-release-notes/main.go
Original file line number Diff line number Diff line change
@@ -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)
}
43 changes: 43 additions & 0 deletions .github/scripts/extract-release-notes/main_test.go
Original file line number Diff line number Diff line change
@@ -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")
}
})
}
}
Loading
Loading