Skip to content

fix(cli): read secret values from stdin - #85

Merged
seonghobae merged 29 commits into
mainfrom
agent/secret-stdin-cli
Aug 12, 2026
Merged

fix(cli): read secret values from stdin#85
seonghobae merged 29 commits into
mainfrom
agent/secret-stdin-cli

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Security boundary

config set-secret previously required plaintext provider credentials in process argv. This slice moves secret entry to bounded stdin/getpass, prevents parser reflection, and enforces a complete one-logical-line boundary while preserving the PostgreSQL SecretStore, Fernet bootstrap-key, provider, schema, and review-agent contracts.

Behavior

  • argv contains only the non-secret secret_key;
  • interactive terminals use getpass; inability to disable echo fails closed before visible-input fallback;
  • non-interactive callers may supply exactly one bounded logical stdin line;
  • only one terminal LF or CRLF framing sequence is normalized;
  • LF, CR, vertical tab, form feed, ASCII file/group/record separators, Unicode Next Line (U+0085), U+2028, and U+2029 are rejected before store construction/write;
  • empty or >65,536-character values fail closed;
  • rejected legacy positional secret text is replaced by fixed <redacted> before argparse stderr output;
  • rejected runtime secret values are not retained in exported validation messages.

Test-first evidence

Earlier RED→GREEN cycles established stdin/argv behavior, GetPassWarning fail-closed handling, rejected-argument confidentiality, and the complete logical-line separator boundary. CodeRabbit's three inline documentation findings are resolved; predecessor review/check evidence remains development provenance only.

Current exact state

  • Source head: 6418ae959b7a1188ba2bd5b888b862da5aceecdc.
  • Independently resolved protected main: 06f88be7f7c3a3ce5e756bc3bf03f298031a0286.
  • The current head non-destructively merges that protected-main tip into prior source 4d474f941689bad613a03a48318663d845c81b51.
  • Reconciliation preserves current-main provider retry/TLS behavior and exact-source CI governance while retaining this PR's secret-input implementation/tests/docs.
  • Exact-head CI 31543539126, Security Scan 31543539135, and SAST Semgrep 31543539146 are queued; queued evidence is not acceptance.
  • All three CodeRabbit inline review threads are resolved. The historical OpenCode CHANGES_REQUESTED review targets predecessor e68d6453b0d50d27e091f82fae5c8d6365611101 and reports a predecessor central coverage-evidence failure; it is not exact-head acceptance or a current-source finding. A current-head required OpenCode workflow must decide the current state.
  • Live organization policy requires central workflows and review-thread resolution, with approving-review count 0, code-owner review disabled, and no last-push approval requirement.

Dependencies and ownership

Repository-local exact-source governance #88 is now on protected main. Issue #90 CLI cancellation remains a separate ownership lane and must not race this branch or #87.

Merge boundary

Promote to Ready so required current-head semantic/central workflows can evaluate this exact source. Merge only if the unchanged head receives terminal success for every then-live repository/central CI, security, package/provenance and policy gate, remains mergeable against the then-live protected base, and has zero valid unresolved current findings. No predecessor, synthetic, queued, pending, cancelled, skipped, absent, status-only, author-only, infrastructure-only, rate-limited, or failed evidence transfers.

Detailed rationale and APA 7 references remain in docs/doctoring/cli-secret-input.md using MITRE CWE-214 and Python argparse/getpass primary documentation.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@opencode-agent[bot], you've reached your PR review limit, so we couldn't start this review.

Next review available in: 6 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2aabd8fb-f879-463d-8fa5-160f7fb4e9e7

📥 Commits

Reviewing files that changed from the base of the PR and between 20e7fb2 and cae78e7.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • README.md
  • docs/doctoring/cli-secret-input.md
  • pg_llm_batch/cli.py
  • tests/test_cli_secret_unicode_line_boundaries.py
  • tests/test_cli_secret_unicode_line_documentation.py
📝 Walkthrough

Walkthrough

config set-secret은 비밀값을 명령줄 인자로 받지 않습니다. TTY에서는 비에코 프롬프트를 사용하고, 비대화형 환경에서는 제한된 한 논리 행의 표준 입력을 사용합니다. 입력 검증, 저장 흐름, 비노출 동작과 관련 문서를 갱신했습니다.

Changes

CLI 비밀 입력 보안

Layer / File(s) Summary
CLI 입력 계약 및 저장 흐름
pg_llm_batch/cli.py
set-secretsecret_key만 명령줄 인자로 받습니다. 비밀값은 TTY의 getpass 또는 표준 입력에서 읽습니다. 빈 값, 다중 행, 캐리지 리턴, 65,536자 초과 입력은 ConfigError로 거부합니다. 검증된 값만 SecretStore.set_secret에 전달합니다.
보안 입력 검증 테스트
tests/test_cli_secret_input_security.py, tests/test_bootstrap_cli.py
명령줄 평문 거부, 표준 입력 저장, 비에코 입력, 에코 폴백 거부, 입력 형식·크기 검증 및 출력 비노출을 검증합니다.
사용법 및 입력 계약 문서
README.md, docs/doctoring/cli-secret-input.md, CHANGELOG.md
TTY 입력, 제한된 표준 입력 자동화, fail-closed 검증, 비밀값 비노출 요구사항과 보안 참고자료를 문서화합니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant getpass
  participant stdin as sys.stdin
  participant SecretStore
  alt TTY 입력
    CLI->>getpass: 비에코 비밀값 요청
    getpass-->>CLI: 비밀값 반환
  else 비대화형 입력
    CLI->>stdin: 제한된 한 논리 행 읽기
    stdin-->>CLI: 비밀값 반환
  end
  CLI->>CLI: 입력값 검증
  CLI->>SecretStore: 검증된 비밀값 저장
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 평문 secret을 명령줄 인자 대신 표준 입력에서 읽도록 변경한 핵심 내용을 정확하고 간결하게 설명합니다.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/secret-stdin-cli

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae marked this pull request as ready for review August 9, 2026 07:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/doctoring/cli-secret-input.md`:
- Line 29: Update the security statement in the CLI secret input documentation
to limit the claim to captured test output and test logs, or remove “tests” from
the claim; do not imply that test source code or assertions never contain the
supplied plaintext.
- Around line 21-22: Update the interactive terminal behavior in the CLI
secret-input documentation to specify that if getpass.getpass() cannot disable
terminal echo, input must not fall back to visible plaintext entry and the
command must terminate with ConfigError. Preserve the existing no-echo behavior
for successful echo control and document the fail-closed contract covered by
test_interactive_secret_refuses_getpass_echo_fallback.
- Around line 45-53: Update the CI acceptance evidence in the
development-sequence documentation to include the successful CI workflow run for
source head 44ffbe5298022652c497b3e1f0d28790839135e1, including its run ID and
verification of Python 3.10, 3.12, and 3.14 tests. Keep the existing RED run as
fail-first history, and do not count security-scan or review-workflow successes
as test acceptance evidence.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 42dcec3d-21c0-4c0e-872c-00848f15bce8

📥 Commits

Reviewing files that changed from the base of the PR and between bf2cc2e and e88fe90.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • README.md
  • docs/doctoring/cli-secret-input.md
  • pg_llm_batch/cli.py
  • tests/test_bootstrap_cli.py
  • tests/test_cli_secret_input_security.py

Comment thread docs/doctoring/cli-secret-input.md
Comment thread docs/doctoring/cli-secret-input.md Outdated
Comment thread docs/doctoring/cli-secret-input.md

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the exact current source head e68d6453b0d50d27e091f82fae5c8d6365611101 against protected main bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10. Re-evaluate the resolved predecessor-head findings and focus on the CLI secret-input confidentiality boundary, fail-closed getpass echo handling, bounded stdin parsing, and stderr redaction. Do not reuse predecessor-head review evidence.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10"
head="e68d6453b0d50d27e091f82fae5c8d6365611101"

git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== exact changed files ==='
git diff --name-status "$base" "$head"

echo '=== exact implementation diff ==='
git diff --unified=80 "$base" "$head" -- pg_llm_batch/cli.py

echo '=== outlines ==='
ast-grep outline pg_llm_batch/cli.py --items all --view expanded
ast-grep outline tests/test_cli_secret_input_security.py --items all --view expanded

echo '=== focused test diff ==='
git diff --unified=40 "$base" "$head" -- tests/test_cli_secret_input_security.py tests/test_bootstrap_cli.py

echo '=== secret-related definitions and error paths ==='
rg -n -C 5 -P '(^\s*(def|class)\s+.*(secret|Secret|config|Config)|\b(set-secret|SecretStore|ConfigError|getpass|GetPassWarning|stdin|stderr)\b)' \
  pg_llm_batch/cli.py tests/test_cli_secret_input_security.py tests/test_bootstrap_cli.py

Length of output: 49561


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== exception types and formatting ==='
fd -t f -e py . pg_llm_batch tests | sort | xargs -r rg -n -C 5 -P \
  '(^\s*class\s+\w*(Error|Exception)\b|def\s+(set_secret|error|main)\s*\(|raise\s+\w*(Error|Exception)\b|print\(.*stderr|str\([^)]*(exc|error))' \
  || true

echo '=== SecretStore implementation and callers ==='
fd -t f -e py . pg_llm_batch | sort | xargs -r rg -n -C 12 -P \
  '(^\s*class\s+SecretStore\b|^\s*def\s+set_secret\s*\(|\.set_secret\s*\()' \
  || true

echo '=== parser construction and parser-error test cases ==='
fd -t f -e py . tests pg_llm_batch | sort | xargs -r rg -n -C 5 -P \
  '(add_subparsers|add_parser|parse_args|parser\.error|unrecognized arguments|invalid choice|argument .*:|SystemExit)' \
  || true

echo '=== current documentation input and error contract ==='
git show e68d6453b0d50d27e091f82fae5c8d6365611101:docs/doctoring/cli-secret-input.md | nl -ba

Length of output: 98697


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== argparse nested-parser diagnostic reproduction (standard library only) ==='
python - <<'PY'
import argparse
import re
import sys
from contextlib import redirect_stderr
from io import StringIO

class RedactingParser(argparse.ArgumentParser):
    def error(self, message):
        message = re.sub(
            r"(?s)^unrecognized arguments:.*$",
            "unrecognized arguments: <redacted>",
            message,
        )
        super().error(message)

parser = RedactingParser(prog="pg_llm_batch")
commands = parser.add_subparsers(dest="command", required=True)
config = commands.add_parser("config")
config_commands = config.add_subparsers(dest="config_command", required=True)
secret = config_commands.add_parser("set-secret")
secret.add_argument("secret_key")

for argv in (
    ["config", "set-secret", "key", "argv-secret"],
    ["config", "argv-secret"],
):
    captured = StringIO()
    try:
        with redirect_stderr(captured):
            parser.parse_args(argv)
    except SystemExit:
        pass
    print(f"argv={argv!r}")
    print(captured.getvalue())
PY

echo '=== exception hierarchy ==='
sed -n '1,115p' pg_llm_batch/exceptions.py

echo '=== full SecretStore write path ==='
sed -n '264,355p' pg_llm_batch/config.py

echo '=== CLI secret-input documentation ==='
sed -n '1,220p' docs/doctoring/cli-secret-input.md

echo '=== direct tests for main() error redaction and store failures ==='
rg -n -C 8 -P '(main\(|SecretStore|set_secret|stderr|redact|secret.*(error|fail)|error.*secret)' \
  tests/test_cli_secret_input_security.py tests/test_bootstrap_cli.py tests/test_config.py

Length of output: 31024


@seonghobae I reviewed e68d6453b0d50d27e091f82fae5c8d6365611101 against bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10.

I found no new actionable issues.

The reviewed implementation removes the plaintext positional secret argument. It validates stdin input before SecretStore construction. It rejects GetPassWarning before the echoed fallback reads input. It redacts the rejected legacy positional secret from stderr. The storage path does not format the plaintext secret in project-defined errors.

I did not execute the full test suite in this sandbox.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head e68d6453b0d50d27e091f82fae5c8d6365611101.

  • Head SHA: e68d6453b0d50d27e091f82fae5c8d6365611101

  • Workflow run: 31302771937

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (3 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: cli-secret-input.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: cli-secret-input.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test (2 files)"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test (2 files)"]
  R3 --> V3["targeted test run"]
Loading

@opencode-agent

opencode-agent Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: e68d6453b0d50d27e091f82fae5c8d6365611101
  • Workflow run: 31302771937
  • Workflow attempt: 1
  • Gate result: REQUEST_CHANGES (approval step)

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head e68d6453b0d50d27e091f82fae5c8d6365611101.

  • Head SHA: e68d6453b0d50d27e091f82fae5c8d6365611101

  • Workflow run: 31302771937

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (3 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: cli-secret-input.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: cli-secret-input.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test (2 files)"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test (2 files)"]
  R3 --> V3["targeted test run"]
Loading

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact current source head e68d6453b0d50d27e091f82fae5c8d6365611101. All previously returned inline findings are resolved; focus on the argv-redaction, stdin/getpass fail-closed secret-input boundary, and resource-ownership compatibility. Do not reuse predecessor-head or infrastructure-only OpenCode evidence.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10"
head="e68d6453b0d50d27e091f82fae5c8d6365611101"

git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== exact commit range ==='
git diff --name-status "$base" "$head"
git diff --stat "$base" "$head"

echo '=== changed CLI implementation ==='
git diff --unified=100 "$base" "$head" -- pg_llm_batch/cli.py

echo '=== CLI structure ==='
ast-grep outline pg_llm_batch/cli.py --items all --view expanded

echo '=== exceptions, configuration, and SecretStore structure ==='
ast-grep outline pg_llm_batch/exceptions.py --items all --view expanded
ast-grep outline pg_llm_batch/config.py --items all --view expanded

echo '=== relevant CLI source slices ==='
rg -n -C 12 -P \
  '(^\s*(def|class)\s+|ConfigError|SecretStore|getpass|GetPassWarning|stdin|stderr|set-secret|parse_args|ArgumentParser|unrecognized arguments|close\s*\(|__enter__|__exit__)' \
  pg_llm_batch/cli.py pg_llm_batch/exceptions.py pg_llm_batch/config.py

echo '=== focused test diff and structure ==='
git diff --unified=80 "$base" "$head" -- tests/test_cli_secret_input_security.py tests/test_bootstrap_cli.py
ast-grep outline tests/test_cli_secret_input_security.py --items all --view expanded
rg -n -C 8 -P \
  '(argv|unrecognized arguments|stdin|getpass|GetPassWarning|ConfigError|SecretStore|close\s*\(|stderr|secret)' \
  tests/test_cli_secret_input_security.py tests/test_bootstrap_cli.py

echo '=== all project SecretStore lifecycle call sites ==='
fd -t f -e py . pg_llm_batch tests | sort | xargs -r rg -n -C 6 -P \
  '(SecretStore\s*\(|with\s+SecretStore|\.close\s*\(|def\s+__enter__|def\s+__exit__)' || true

echo '=== current documentation contract ==='
sed -n '1,240p' docs/doctoring/cli-secret-input.md

Length of output: 138705


@seonghobae I reviewed exact source head e68d6453b0d50d27e091f82fae5c8d6365611101 against main bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10.

I found no new actionable issues in the requested scope.

config set-secret no longer accepts a plaintext value as a positional argument. The parser redacts the rejected legacy value from the unrecognized arguments: diagnostic.

The TTY path promotes getpass.GetPassWarning to ConfigError. This stops the echoed fallback before it can read the secret.

The non-interactive path reads a bounded value. It removes only one terminal LF or CRLF. It rejects empty, multiline, carriage-return-containing, and oversized values before SecretStore construction.

The changed set-secret path preserves the existing SecretStore ownership model. It does not introduce a new resource lifecycle incompatibility.

I used new source evidence only. I did not execute project code or tests.

You are interacting with an AI system.

@seonghobae
seonghobae marked this pull request as draft August 10, 2026 03:42
@seonghobae
seonghobae marked this pull request as ready for review August 11, 2026 22:43
@seonghobae
seonghobae merged commit 7a6a021 into main Aug 12, 2026
31 checks passed
@seonghobae
seonghobae deleted the agent/secret-stdin-cli branch August 12, 2026 00:08
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.

1 participant