Skip to content

feat: aiterm v0.2.0 (tests, CI, releases, security fixes) - #9

Merged
Thakay merged 12 commits into
mainfrom
claude/aiterm-oss-pro-prep-672m0z
Oct 4, 2026
Merged

Thakay merged 12 commits into
mainfrom
claude/aiterm-oss-pro-prep-672m0z

Conversation

@Thakay

@Thakay Thakay commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Summary

Prepares aiterm for its v0.2.0 release: fixes real bugs, adds tests, CI and automated releases, and adds the community files a healthy open source project needs.

Why now: OpenAI shuts down gpt-3.5-turbo, aiterm's default model, on 2026-10-23. Without this change aiterm stops working on that date. The default is now gpt-4.1-mini, and -model works with any model, including reasoning models.

Bugs fixed

  • A missing API key was never detected (hasAPIKey always returned true), so requests went out unauthenticated.
  • aiterm -h printed the value of OPENAI_KEY.
  • HTTP requests had no timeout and could hang forever.
  • aiterm looped forever when stdin closed after a "not a command" reply.
  • The README clone URL pointed to yourgithubusername, and the module path was still github.com/thakay/goterm, so go install could not work.

Security hardening

  • Model replies containing control characters, escape sequences, bidi overrides or zero width characters are refused. A carriage return could make the terminal show ls while sh ran something else.
  • A flag typed after the request (aiterm list files -key sk-...) is now an error, instead of being sent to the model as text.
  • A key typed at the prompt is not echoed. Responses are capped at 1 MiB. Plain http to a remote host prints a warning.

New

  • -model, -timeout, -version, AITERM_MODEL, AITERM_URL, AITERM_TIMEOUT; unquoted prompts; OS aware system prompt; streamed command output; Ctrl+C returns to the menu; multi line commands are flagged.
  • Tests: unit, end-to-end (httptest server) and fuzz tests, about 96% coverage, no network.
  • CI: Linux and macOS with the two supported Go releases, race detector, fuzzing, golangci-lint, a GoReleaser snapshot build, CodeQL, govulncheck, OpenSSF Scorecard and Dependabot. Every action is pinned to a commit SHA.
  • Releases: pushing a v* tag builds reproducible Linux and macOS binaries (amd64 and arm64) with checksums and publishes the CHANGELOG section as release notes.
  • CHANGELOG, CONTRIBUTING, SECURITY, Code of Conduct, AGENTS.md, issue forms, PR template, Makefile.

Related issue

Closes #1
Closes #2

The README roadmap now links to #3, #4, #5, #6, #7 and #8.

Type of change

  • Bug fix (fixes a problem without changing intended behavior)
  • New feature (adds functionality without breaking existing usage)
  • Breaking change (changes existing flags, environment variables, output or exit codes)
  • Documentation only
  • Tests, CI, build or refactoring (no user facing change)

Breaking changes are small: running without a prompt now exits with 2 instead of 0, flags must come before the request, and building from source needs Go 1.26 (Go 1.21+ downloads it automatically).

Checklist

  • I added or updated tests for this change.
  • make test and make lint pass locally (golangci-lint 2.14, Go 1.26 and 1.27).
  • I added an entry in CHANGELOG.md for user facing changes (the 0.2.0 section).
  • I updated the docs (README.md, aiterm -h help text) where needed.
  • My commits and the pull request title follow Conventional Commits.

Also verified locally: actionlint and zizmor report no findings on the workflows, goreleaser check passes, a GoReleaser snapshot produces the four archives the README links to, and govulncheck reports no vulnerabilities on Go 1.27. Not verified yet: the macOS CI legs and a live OpenAI request (no key available).

Before and after merging

  1. Before merging, enable private vulnerability reporting (Settings > Code security). SECURITY.md and the issue templates link to it.
  2. Right after merging, push the release tag. Until it exists, the README download links return 404 and go install resolves to the old beta:
    git checkout main && git pull
    git tag -a v0.2.0 -m "aiterm v0.2.0" && git push origin v0.2.0
  3. Mark the v0.1.0-beta.1 release as a pre-release so releases/latest points at v0.2.0.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK


Generated by Claude Code

claude added 12 commits October 4, 2026 00:29
The module was still declared as github.com/thakay/goterm, so
`go install github.com/Thakay/aiterm@latest` could not work. Also remove
the committed JetBrains .idea folder, add a .gitignore, and use the
conventional README.md name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
- hasAPIKey always returned true, so a missing key was never noticed and
  requests went out unauthenticated instead of prompting for a key.
- Use an HTTP client with a 60s timeout instead of http.DefaultClient.
- Default to gpt-4.1-mini. OpenAI shuts gpt-3.5-turbo down on 2026-10-23.
- Name the operating system in the system prompt so macOS gets BSD flags.
- Only commit a request to the conversation history once it succeeded.
- Report non JSON error pages with their HTTP status, and treat any 401
  as an invalid key.
- Treat only 2xx as success (300 was accepted before).
- Stop calling log.Fatal from library code.
- Error types implement Unwrap, and the unmarshaling error no longer
  says "marshaling".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
- New -model flag and AITERM_MODEL / AITERM_URL environment variables.
- New -version flag; release builds get version, commit and date via
  ldflags, `go install` builds fall back to the module version.
- -h no longer prints the value of OPENAI_KEY as the -key default.
- Prompts no longer need quotes: all positional arguments are joined.
- Missing prompt or bad flags exit with status 2, runtime errors with 1.
- Command output streams to the terminal, and a failing command returns
  to the menu instead of aborting aiterm.
- Strip markdown fences, backticks and "$ " prompts from model replies.
- Print the command when the clipboard is unavailable instead of failing.
- Stop looping forever when stdin closes after a "not a command" reply.
- Inject stdin/stdout/stderr and the clipboard so the app is testable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
Adds table driven unit tests with a scripted fake provider, end-to-end
tests that run the CLI against an httptest chat completions server, and
a subprocess test for main's exit codes. No test touches the network.
Statement coverage is about 96%.

Closes #1
Closes #2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
- Fix the clone URL (it still pointed at "yourgithubusername").
- Add CI, release, Go Report Card and Go version badges.
- Document release binaries, `go install`, every flag and environment
  variable, local models through Ollama, and the interactive menu.
- Replace the placeholder contact email with the issue tracker.
- Add a roadmap and a development section.
- Add CHANGELOG.md in Keep a Changelog format with the 0.2.0 notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
Enables the standard linters plus bodyclose, errorlint, gocritic,
misspell, revive and unconvert, with gofmt and goimports as formatters.
Clean on golangci-lint 2.5 and 2.14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
Security:
- Refuse model replies that contain control characters, escape
  sequences, bidi overrides or zero width characters. A carriage return
  or an escape sequence could make the terminal show one command while
  sh runs another.
- Reject flags typed after the request instead of sending them to the
  model as text (a -key value would have been sent as part of the
  request). `--` still allows flag-like words in a request.
- Read a key typed at the prompt without echoing it (golang.org/x/term).
- Cap responses at 1 MiB.
- Warn when the API key would go over plain http to a remote host.

Fixes and improvements:
- Stop sending max_tokens and sampling parameters. Reasoning models
  reject them, so -model now works with any model.
- New -timeout flag and AITERM_TIMEOUT, default 2m (was a fixed 60s that
  slow local models could hit). Timeouts explain how to raise the limit.
- Ask for a new key when the key is rejected, like 0.1.0-beta.1 did.
- Ctrl+C stops a running command and returns to the menu.
- Warn before running a multi line command.
- Handle CRLF replies, any fence info string, and "$ " on every line.
- Print the same version format for release and go install builds.
- Require Go 1.26, the oldest Go release that still gets security fixes.

Tests: cases for all of the above, a test that nothing runs unless the
user enters y, and FuzzValidateCmd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
- CI runs build, vet and the race-enabled tests on Linux and macOS with
  the two supported Go releases, fuzzes the reply validation, runs
  golangci-lint, checks go.mod is tidy, and builds a GoReleaser snapshot
  to make sure the archives the README links to are produced.
- CodeQL and govulncheck run on every change and weekly.
- OpenSSF Scorecard publishes the repository's security posture.
- Dependabot updates Go modules and GitHub Actions weekly.
- Every action is pinned to a commit SHA with its version as a comment,
  checkouts do not persist credentials, and tokens are read only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
Pushing a v* tag runs the tests, builds static Linux and macOS binaries
for amd64 and arm64, and publishes a GitHub release with checksums. The
release notes are taken from the matching CHANGELOG.md section. Builds
are reproducible (commit time for the embedded date and file times),
use a clean module cache, and the job is the only one with write access.

The Makefile wraps build, test, cover, fuzz, lint, fmt, tidy, vuln,
snapshot and clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
…S.md

- CONTRIBUTING.md: setup, Makefile targets, CI, project layout, how to
  add a provider, commit conventions and the release process.
- SECURITY.md: supported versions, private reporting, the security
  model, and what is in and out of scope.
- CODE_OF_CONDUCT.md: Contributor Covenant 2.1.
- AGENTS.md: commands and rules for coding agents such as Codex.
- Issue forms for bugs and feature requests, a security contact link,
  and a pull request template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
…gelog

- README: -timeout/AITERM_TIMEOUT, flags before the request, when to
  quote a request, checksum verification, curl -f, key handling without
  shell history, the hidden character guard, and the make targets.
- CHANGELOG: the 0.1.0-beta.1 entry claimed follow-up requests that only
  arrived after that tag, so list them under 0.2.0; only the missing
  prompt case changed exit status; add a Security section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkUHjJxVa3yTdFB87BrwFK
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@Thakay
Thakay merged commit ee8165c into main Oct 4, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add test for app.go Add test for mian.go

3 participants