From d8ec02250c3dff51e7d69ea2f390b5edce4c3819 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 11:59:43 +0800 Subject: [PATCH 01/15] =?UTF-8?q?feat(codex):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=89=E8=A3=9D=20Codex=20CLI=E3=80=81=E5=AF=AB=E5=85=A5=20O?= =?UTF-8?q?Auth=20token=20=E4=B8=A6=E5=9F=B7=E8=A1=8C=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=A9=9E=E7=9A=84=20composite=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action.yml | 55 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/action.yml b/action.yml index 646c3c6..457fc47 100644 --- a/action.yml +++ b/action.yml @@ -1,33 +1,48 @@ -name: 'Composite Action Template' -description: 'Composite Action 範本' +name: 'Codex CLI' +description: 'Codex CLI 工具' author: 'Jeffery' inputs: - text: - description: '輸入的文字' + prompt: + description: '傳給 Codex CLI 的提示詞' required: false - default: 'Hello, World!' + default: "請自我介紹" + oauth: + description: 'base64 編碼的 Codex OAuth token 檔案內容' + required: true outputs: text: description: '輸出的文字' - value: ${{ steps.change.outputs.text }} + value: ${{ steps.codex.outputs.text }} runs: using: 'composite' steps: - - name: 交換 - id: change + - name: 安裝工具 env: - GITEA_SERVER_URL: ${{ gitea.server_url }} - GITEA_REPOSITORY: ${{ gitea.repository }} - GITEA_TOKEN: ${{ gitea.token }} - TEXT: ${{ inputs.text }} + OAUTH: ${{ inputs.oauth }} run: | - echo "Gitea Server Url: $GITEA_SERVER_URL" + npm install -g @openai/codex - echo "Gitea Repository: $GITEA_REPOSITORY" + oauth_file="$HOME/.codex/auth.json" + install -d -m 700 "$(dirname "$oauth_file")" + printf '%s' "$OAUTH" | base64 -d > "$oauth_file" + chmod 600 "$oauth_file" + shell: bash + - name: 執行工具 + id: codex + env: + MODEL: ${{ vars.CODEX_MODEL }} + PROMPT: ${{ inputs.prompt }} + run: | + if [ -z "$MODEL" ]; then + echo 'CODEX_MODEL repository variable is required.' >&2 + exit 1 + fi - echo "Gitea Token: $GITEA_TOKEN" - - echo "Text: $TEXT" - - echo "text=$TEXT" >> "$GITHUB_OUTPUT" - shell: bash \ No newline at end of file + text="$(codex exec --model "$MODEL" "$PROMPT")" + printf '%s\n' "$text" + { + echo 'text<> "$GITHUB_OUTPUT" + shell: bash -- 2.53.0 From dc9ab5f2357748b4509c7432c1c0bd2f6a190d88 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 11:59:43 +0800 Subject: [PATCH 02/15] =?UTF-8?q?chore(ci):=20=E6=94=B9=E7=94=A8=20release?= =?UTF-8?q?-tag-version=20=E8=A8=88=E7=AE=97=E7=89=88=E6=9C=AC=E4=B8=A6?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=20codex=20=E6=B8=AC=E8=A9=A6=E4=BB=BB?= =?UTF-8?q?=E5=8B=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci.yaml | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 15c4240..a351fbc 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -1,19 +1,35 @@ name: CI + on: pull_request: branches-ignore: - master types: [opened, synchronize] + jobs: - ai-code-review: - name: AI Code Review + release-tag-version: + name: Release Tag Version runs-on: ubuntu - permissions: - contents: write - pull-requests: write - issues: write + outputs: + version: ${{ steps.release-tag-version.outputs.version }} steps: - - name: AI 程式碼審查 by OpenCode - uses: https://gitea.jsc.idv.tw/composite-actions/opencode-code-review@${{ vars.ACTION_OPENCODE_CODE_REVIEW_VERSION }} + - name: 計算版本號 + id: release-tag-version + uses: https://gitea.jsc.idv.tw/composite-actions/release-tag-version@${{ vars.ACTION_RELEASE_TAG_VERSION }} with: - token: ${{ secrets.TOKEN }} + is_beta: 'true' + + codex: + name: Codex + runs-on: ubuntu + needs: release-tag-version + steps: + - name: 測試工具 + id: codex + uses: https://gitea.jsc.idv.tw/composite-actions/codex@v${{ needs.release-tag-version.outputs.version }} + with: + oauth: ${{ secrets.CODEX_OAUTH }} + prompt: "請告訴我目前登入的帳號,只要電子郵件不要其他任何資訊" + - name: 檢查輸出 + if: ${{ steps.codex.outputs.text != vars.CODEX_EMAIL }} + run: exit 1 -- 2.53.0 From 5a21b30e9c9a7506622ba8a262db6f426ec5c456 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 11:59:43 +0800 Subject: [PATCH 03/15] =?UTF-8?q?docs(README):=20=E6=96=B0=E5=A2=9E=20Code?= =?UTF-8?q?x=20CLI=20composite=20action=20=E4=BD=BF=E7=94=A8=E8=AA=AA?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..1f59026 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# Codex CLI Composite Action + +此 repository 提供一個 Gitea/GitHub Actions composite action,用於安裝 Codex CLI、寫入 OAuth token、執行指定提示詞,並將 CLI 輸出寫入 action output。 + +## 專案列表 + +### 專案描述 + +| 專案名稱 | 專案描述 | +| --- | --- | +| [codex](https://gitea.jsc.idv.tw/composite-actions/codex) | 提供 Codex CLI composite action,讓 workflow 可透過 `oauth` 與 `prompt` 輸入執行 CLI,並從 repository variable 讀取模型名稱後取得文字輸出。 | + +### 參考專案 + +| 專案名稱 | 參考專案列表 | +| --- | --- | +| [codex](https://gitea.jsc.idv.tw/composite-actions/codex) | 無 | + +### NuGet 套件 + +| 專案名稱 | NuGet 套件列表 | +| --- | --- | +| [codex](https://gitea.jsc.idv.tw/composite-actions/codex) | 無 | + +## 功能列表 + +此 repository 未包含可列入 README 的 public method、public constructor、public extension method 或 public operator。 + +## 使用範例 + +### 在 workflow 中呼叫 Codex CLI + +以下範例示範在 workflow step 中呼叫此 composite action,傳入 OAuth token 與提示詞,並在後續步驟讀取 `text` output。模型名稱由 action 直接讀取 `vars.CODEX_MODEL`。 + +```yaml +- name: 執行 Codex CLI + id: codex + uses: https://gitea.jsc.idv.tw/composite-actions/codex@v1 + with: + oauth: ${{ secrets.CODEX_OAUTH }} + prompt: "請自我介紹" + +- name: 使用輸出文字 + run: printf '%s\n' '${{ steps.codex.outputs.text }}' +``` + +前置條件: + +- `secrets.CODEX_OAUTH` 必須是 Codex OAuth token 檔案內容的 base64 字串。 +- `vars.CODEX_MODEL` 必須是 Codex CLI 可用的模型名稱。 +- runner 必須可透過 npm 安裝 `@openai/codex`。 + +預期結果: + +- action 會安裝 `codex` CLI。 +- action 會將 OAuth token 寫入 `$HOME/.codex/auth.json` 並設定檔案權限為 `600`。 +- action 會執行 `codex exec --model "$MODEL" "$PROMPT"`,並把 stdout 寫入 `steps.codex.outputs.text`。 -- 2.53.0 From e4fc162b55f09a87b5d329dcaeca77d19f2f2e6d Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 12:17:04 +0800 Subject: [PATCH 04/15] =?UTF-8?q?fix(codex):=20=E7=82=BA=20codex=20exec=20?= =?UTF-8?q?=E5=8A=A0=E4=B8=8A=20--skip-git-repo-check=20=E4=BB=A5=E7=95=A5?= =?UTF-8?q?=E9=81=8E=20git=20repo=20=E6=AA=A2=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 457fc47..4a75eaf 100644 --- a/action.yml +++ b/action.yml @@ -38,7 +38,7 @@ runs: exit 1 fi - text="$(codex exec --model "$MODEL" "$PROMPT")" + text="$(codex exec --skip-git-repo-check --model "$MODEL" "$PROMPT")" printf '%s\n' "$text" { echo 'text< Date: Mon, 29 Jun 2026 12:28:43 +0800 Subject: [PATCH 05/15] =?UTF-8?q?fix(codex):=20=E4=BF=AE=E6=AD=A3=20runner?= =?UTF-8?q?=20=E6=B2=99=E7=AE=B1=E4=B8=A6=E6=94=B9=E4=BB=A5=20OAuth=20id?= =?UTF-8?q?=5Ftoken=20=E7=9A=84=20email=20=E9=A9=97=E8=AD=89=E7=99=BB?= =?UTF-8?q?=E5=85=A5=E5=B8=B3=E8=99=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit codex exec 加上 -s danger-full-access 避免 runner 容器內 bubblewrap 因 無法建立 user namespace 而失敗;action 新增 email output(解析 auth.json id_token 的 email claim),CI 改用 steps.codex.outputs.email 比對 vars.CODEX_EMAIL,不再依賴模型自行回報帳號。 --- .gitea/workflows/ci.yaml | 6 +++--- action.yml | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index a351fbc..373af0d 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -29,7 +29,7 @@ jobs: uses: https://gitea.jsc.idv.tw/composite-actions/codex@v${{ needs.release-tag-version.outputs.version }} with: oauth: ${{ secrets.CODEX_OAUTH }} - prompt: "請告訴我目前登入的帳號,只要電子郵件不要其他任何資訊" - - name: 檢查輸出 - if: ${{ steps.codex.outputs.text != vars.CODEX_EMAIL }} + prompt: "請自我介紹" + - name: 檢查登入帳號 + if: ${{ steps.codex.outputs.email != vars.CODEX_EMAIL }} run: exit 1 diff --git a/action.yml b/action.yml index 4a75eaf..b18fc6d 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,9 @@ outputs: text: description: '輸出的文字' value: ${{ steps.codex.outputs.text }} + email: + description: '目前登入帳號的電子郵件(取自 OAuth id_token)' + value: ${{ steps.codex.outputs.email }} runs: using: 'composite' steps: @@ -38,11 +41,23 @@ runs: exit 1 fi - text="$(codex exec --skip-git-repo-check --model "$MODEL" "$PROMPT")" + text="$(codex exec --skip-git-repo-check -s danger-full-access --model "$MODEL" "$PROMPT")" printf '%s\n' "$text" + + # 從 OAuth id_token(JWT)解出目前登入帳號的 email;正規表示式對冒號後空白容錯 + auth_file="$HOME/.codex/auth.json" + id_token="$(grep -oE -m1 '"id_token"[[:space:]]*:[[:space:]]*"[^"]*"' "$auth_file" | sed -E 's/.*:[[:space:]]*"//; s/"$//' || true)" + payload="$(printf '%s' "$id_token" | cut -d. -f2 | tr '_-' '/+')" + case $((${#payload} % 4)) in + 2) payload="${payload}==" ;; + 3) payload="${payload}=" ;; + esac + email="$(printf '%s' "$payload" | base64 -d 2>/dev/null | grep -oE -m1 '"email"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*:[[:space:]]*"//; s/"$//' || true)" + { echo 'text<> "$GITHUB_OUTPUT" shell: bash -- 2.53.0 From 7ee6921c638fa95597c5f2e97c4076e350fa6e06 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 12:35:35 +0800 Subject: [PATCH 06/15] =?UTF-8?q?fix(codex):=20=E6=94=B9=E4=BB=A5=20codex?= =?UTF-8?q?=20exec=20=E7=9C=9F=E5=AF=A6=E5=BE=80=E8=BF=94=E9=A9=97?= =?UTF-8?q?=E8=AD=89=E7=99=BB=E5=85=A5=EF=BC=8C=E7=A7=BB=E9=99=A4=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E8=A7=A3=E6=9E=90=20OAuth=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 不再解析 auth.json 的 id_token 來取得 email(只證明 secret 解得開、 無法確保工具真的登入成功)。改為透過 codex exec 實際呼叫模型:登入無效 或 token 過期時 codex exec 會直接失敗,CI 再以 steps.codex.outputs.text 是否為空做最終把關。action 移除 email output,保留 -s danger-full-access 以避免 runner 容器內 bubblewrap 沙箱失敗。 --- .gitea/workflows/ci.yaml | 4 ++-- action.yml | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 373af0d..6b8066b 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -30,6 +30,6 @@ jobs: with: oauth: ${{ secrets.CODEX_OAUTH }} prompt: "請自我介紹" - - name: 檢查登入帳號 - if: ${{ steps.codex.outputs.email != vars.CODEX_EMAIL }} + - name: 檢查登入 + if: ${{ steps.codex.outputs.text == '' }} run: exit 1 diff --git a/action.yml b/action.yml index b18fc6d..78beab2 100644 --- a/action.yml +++ b/action.yml @@ -13,9 +13,6 @@ outputs: text: description: '輸出的文字' value: ${{ steps.codex.outputs.text }} - email: - description: '目前登入帳號的電子郵件(取自 OAuth id_token)' - value: ${{ steps.codex.outputs.email }} runs: using: 'composite' steps: @@ -43,21 +40,9 @@ runs: text="$(codex exec --skip-git-repo-check -s danger-full-access --model "$MODEL" "$PROMPT")" printf '%s\n' "$text" - - # 從 OAuth id_token(JWT)解出目前登入帳號的 email;正規表示式對冒號後空白容錯 - auth_file="$HOME/.codex/auth.json" - id_token="$(grep -oE -m1 '"id_token"[[:space:]]*:[[:space:]]*"[^"]*"' "$auth_file" | sed -E 's/.*:[[:space:]]*"//; s/"$//' || true)" - payload="$(printf '%s' "$id_token" | cut -d. -f2 | tr '_-' '/+')" - case $((${#payload} % 4)) in - 2) payload="${payload}==" ;; - 3) payload="${payload}=" ;; - esac - email="$(printf '%s' "$payload" | base64 -d 2>/dev/null | grep -oE -m1 '"email"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*:[[:space:]]*"//; s/"$//' || true)" - { echo 'text<> "$GITHUB_OUTPUT" shell: bash -- 2.53.0 From 6e771e2e5233b6e53a5e226f844e7d7df61ba186 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 12:48:48 +0800 Subject: [PATCH 07/15] =?UTF-8?q?fix(codex):=20=E6=94=B9=E7=94=A8=20codex?= =?UTF-8?q?=20app-server=20account/read=20=E5=8F=96=E5=BE=97=E7=99=BB?= =?UTF-8?q?=E5=85=A5=E5=B8=B3=E8=99=9F=20email=20=E9=A9=97=E8=AD=89?= =?UTF-8?q?=E8=BA=AB=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 不解析本地 OAuth token,改透過 codex 自身的 app-server JSON-RPC account/read(即 TUI /status 的 Account 來源)取得登入帳號 email, 新增 email output;CI 以 steps.codex.outputs.email 比對 vars.CODEX_EMAIL 確認是正確帳號。codex exec 仍保留以確保 token 實際有效。 --- .gitea/workflows/ci.yaml | 4 ++-- action.yml | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 6b8066b..373af0d 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -30,6 +30,6 @@ jobs: with: oauth: ${{ secrets.CODEX_OAUTH }} prompt: "請自我介紹" - - name: 檢查登入 - if: ${{ steps.codex.outputs.text == '' }} + - name: 檢查登入帳號 + if: ${{ steps.codex.outputs.email != vars.CODEX_EMAIL }} run: exit 1 diff --git a/action.yml b/action.yml index 78beab2..51f1987 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,9 @@ outputs: text: description: '輸出的文字' value: ${{ steps.codex.outputs.text }} + email: + description: '目前登入帳號的電子郵件(由 codex app-server account/read 取得)' + value: ${{ steps.account.outputs.email }} runs: using: 'composite' steps: @@ -46,3 +49,45 @@ runs: echo 'CODEX_OUTPUT' } >> "$GITHUB_OUTPUT" shell: bash + - name: 取得登入帳號 + id: account + run: | + cat > "$RUNNER_TEMP/codex_account.py" <<'PY' + import json, subprocess, time + + p = subprocess.Popen( + ["codex", "app-server"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, text=True, bufsize=1, + ) + + def send(obj): + p.stdin.write(json.dumps(obj) + "\n") + p.stdin.flush() + + send({"jsonrpc": "2.0", "id": 1, "method": "initialize", + "params": {"clientInfo": {"name": "ci", "version": "1.0"}}}) + send({"jsonrpc": "2.0", "method": "initialized", "params": {}}) + send({"jsonrpc": "2.0", "id": 2, "method": "account/read", "params": {}}) + + email = "" + deadline = time.time() + 25 + while time.time() < deadline: + line = p.stdout.readline() + if not line: + break + try: + msg = json.loads(line) + except Exception: + continue + if msg.get("id") == 2: + account = (msg.get("result") or {}).get("account") or {} + email = account.get("email") or "" + break + + p.terminate() + print(email) + PY + email="$(python3 "$RUNNER_TEMP/codex_account.py")" + printf 'email=%s\n' "$email" >> "$GITHUB_OUTPUT" + shell: bash -- 2.53.0 From 672900762ec8927d25631c2578af1c56fba27e17 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 12:52:01 +0800 Subject: [PATCH 08/15] =?UTF-8?q?refactor(codex):=20=E5=B0=87=20app-server?= =?UTF-8?q?=20=E5=8F=96=E5=B8=B3=E8=99=9F=E9=82=8F=E8=BC=AF=E6=8A=BD?= =?UTF-8?q?=E5=88=B0=20app/codex=5Faccount.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把原本內嵌在 action.yml heredoc 的 python 抽成獨立檔 app/codex_account.py, action 改以 $GITHUB_ACTION_PATH/app/codex_account.py 呼叫,便於閱讀與維護。 --- action.yml | 38 +---------------------------- app/codex_account.py | 57 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 app/codex_account.py diff --git a/action.yml b/action.yml index 51f1987..0a325e9 100644 --- a/action.yml +++ b/action.yml @@ -52,42 +52,6 @@ runs: - name: 取得登入帳號 id: account run: | - cat > "$RUNNER_TEMP/codex_account.py" <<'PY' - import json, subprocess, time - - p = subprocess.Popen( - ["codex", "app-server"], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, text=True, bufsize=1, - ) - - def send(obj): - p.stdin.write(json.dumps(obj) + "\n") - p.stdin.flush() - - send({"jsonrpc": "2.0", "id": 1, "method": "initialize", - "params": {"clientInfo": {"name": "ci", "version": "1.0"}}}) - send({"jsonrpc": "2.0", "method": "initialized", "params": {}}) - send({"jsonrpc": "2.0", "id": 2, "method": "account/read", "params": {}}) - - email = "" - deadline = time.time() + 25 - while time.time() < deadline: - line = p.stdout.readline() - if not line: - break - try: - msg = json.loads(line) - except Exception: - continue - if msg.get("id") == 2: - account = (msg.get("result") or {}).get("account") or {} - email = account.get("email") or "" - break - - p.terminate() - print(email) - PY - email="$(python3 "$RUNNER_TEMP/codex_account.py")" + email="$(python3 "$GITHUB_ACTION_PATH/app/codex_account.py")" printf 'email=%s\n' "$email" >> "$GITHUB_OUTPUT" shell: bash diff --git a/app/codex_account.py b/app/codex_account.py new file mode 100644 index 0000000..10f5648 --- /dev/null +++ b/app/codex_account.py @@ -0,0 +1,57 @@ +"""透過 codex app-server 的 JSON-RPC account/read 取得目前登入帳號的 email。 + +這是 TUI `/status` Account 欄位的程式化來源,不解析本地 OAuth token, +而是由 codex 自身回報登入帳號。將 email 印到 stdout(取不到時印空字串)。 +""" + +import json +import subprocess +import time + + +def read_account_email(timeout_seconds: float = 25.0) -> str: + process = subprocess.Popen( + ["codex", "app-server"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + text=True, + bufsize=1, + ) + + def send(obj): + process.stdin.write(json.dumps(obj) + "\n") + process.stdin.flush() + + send({ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": {"clientInfo": {"name": "ci", "version": "1.0"}}, + }) + send({"jsonrpc": "2.0", "method": "initialized", "params": {}}) + send({"jsonrpc": "2.0", "id": 2, "method": "account/read", "params": {}}) + + email = "" + deadline = time.time() + timeout_seconds + try: + while time.time() < deadline: + line = process.stdout.readline() + if not line: + break + try: + message = json.loads(line) + except ValueError: + continue + if message.get("id") == 2: + account = (message.get("result") or {}).get("account") or {} + email = account.get("email") or "" + break + finally: + process.terminate() + + return email + + +if __name__ == "__main__": + print(read_account_email()) -- 2.53.0 From d05610d4e56bb4cca1f86977a66b1e8e36036faf Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 12:56:00 +0800 Subject: [PATCH 09/15] =?UTF-8?q?refactor(codex):=20oauth=20=E6=94=B9?= =?UTF-8?q?=E5=BE=9E=20secrets=20=E5=8F=96=E5=BE=97=E3=80=81=E5=B8=B3?= =?UTF-8?q?=E8=99=9F=E9=A9=97=E8=AD=89=E6=94=B6=E9=80=B2=20action=20?= =?UTF-8?q?=E5=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit oauth 不再經由 inputs 傳入,action 直接讀 secrets.CODEX_OAUTH(與 vars.CODEX_MODEL 相同模式)。登入帳號驗證移入 action:讀 vars.CODEX_EMAIL 與 app-server 取得的 email 比對,不再輸出 email 到 outputs、不在 CI 端比對。 --- .gitea/workflows/ci.yaml | 4 ---- action.yml | 24 ++++++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 373af0d..40ec896 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -28,8 +28,4 @@ jobs: id: codex uses: https://gitea.jsc.idv.tw/composite-actions/codex@v${{ needs.release-tag-version.outputs.version }} with: - oauth: ${{ secrets.CODEX_OAUTH }} prompt: "請自我介紹" - - name: 檢查登入帳號 - if: ${{ steps.codex.outputs.email != vars.CODEX_EMAIL }} - run: exit 1 diff --git a/action.yml b/action.yml index 0a325e9..2886409 100644 --- a/action.yml +++ b/action.yml @@ -6,22 +6,16 @@ inputs: description: '傳給 Codex CLI 的提示詞' required: false default: "請自我介紹" - oauth: - description: 'base64 編碼的 Codex OAuth token 檔案內容' - required: true outputs: text: description: '輸出的文字' value: ${{ steps.codex.outputs.text }} - email: - description: '目前登入帳號的電子郵件(由 codex app-server account/read 取得)' - value: ${{ steps.account.outputs.email }} runs: using: 'composite' steps: - name: 安裝工具 env: - OAUTH: ${{ inputs.oauth }} + OAUTH: ${{ secrets.CODEX_OAUTH }} run: | npm install -g @openai/codex @@ -49,9 +43,19 @@ runs: echo 'CODEX_OUTPUT' } >> "$GITHUB_OUTPUT" shell: bash - - name: 取得登入帳號 - id: account + - name: 驗證登入帳號 + env: + EXPECTED_EMAIL: ${{ vars.CODEX_EMAIL }} run: | + if [ -z "$EXPECTED_EMAIL" ]; then + echo 'CODEX_EMAIL repository variable is required.' >&2 + exit 1 + fi + email="$(python3 "$GITHUB_ACTION_PATH/app/codex_account.py")" - printf 'email=%s\n' "$email" >> "$GITHUB_OUTPUT" + if [ "$email" != "$EXPECTED_EMAIL" ]; then + echo '登入帳號與 CODEX_EMAIL 不符' >&2 + exit 1 + fi + echo '登入帳號驗證通過' shell: bash -- 2.53.0 From 08890b5b9d99e8517bdcef86b234dfe21828a19e Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 13:35:42 +0800 Subject: [PATCH 10/15] =?UTF-8?q?fix(codex):=20=E6=94=B9=E7=94=B1=20job=20?= =?UTF-8?q?=E5=B1=A4=20env=20=E5=BE=9E=20secrets=20=E6=B3=A8=E5=85=A5=20CO?= =?UTF-8?q?DEX=5FOAUTH?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit composite action 內無法解析 secrets context(Gitea 與 GitHub 皆然, vars 可、secrets 不可),導致 OAUTH 為空。改由呼叫端 workflow 在 job 層 以 env: CODEX_OAUTH: ${{ secrets.CODEX_OAUTH }} 注入,action 從繼承的 環境變數讀取並加空值把關;secret 仍源自 secrets、不經 inputs 傳遞。 --- .gitea/workflows/ci.yaml | 2 ++ action.yml | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 40ec896..3db0222 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -23,6 +23,8 @@ jobs: name: Codex runs-on: ubuntu needs: release-tag-version + env: + CODEX_OAUTH: ${{ secrets.CODEX_OAUTH }} steps: - name: 測試工具 id: codex diff --git a/action.yml b/action.yml index 2886409..80abb0a 100644 --- a/action.yml +++ b/action.yml @@ -14,14 +14,17 @@ runs: using: 'composite' steps: - name: 安裝工具 - env: - OAUTH: ${{ secrets.CODEX_OAUTH }} run: | + if [ -z "$CODEX_OAUTH" ]; then + echo 'CODEX_OAUTH environment variable is required (set it from secrets.CODEX_OAUTH in the caller workflow).' >&2 + exit 1 + fi + npm install -g @openai/codex oauth_file="$HOME/.codex/auth.json" install -d -m 700 "$(dirname "$oauth_file")" - printf '%s' "$OAUTH" | base64 -d > "$oauth_file" + printf '%s' "$CODEX_OAUTH" | base64 -d > "$oauth_file" chmod 600 "$oauth_file" shell: bash - name: 執行工具 -- 2.53.0 From a309afdf58bfb02a259a3468b3446e7f6858050d Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 13:42:36 +0800 Subject: [PATCH 11/15] =?UTF-8?q?fix(codex):=20oauth=20=E6=94=B9=E5=9B=9E?= =?UTF-8?q?=E7=B6=93=20inputs.oauth=20=E5=82=B3=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit composite action 讀不到 secrets context,改回由呼叫端以 with: oauth: ${{ secrets.CODEX_OAUTH }} 經 inputs.oauth 傳入;action 從 inputs.oauth 讀取並保留空值把關,移除 job 層 CODEX_OAUTH env。 --- .gitea/workflows/ci.yaml | 3 +-- action.yml | 11 ++++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 3db0222..d8d33d5 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -23,11 +23,10 @@ jobs: name: Codex runs-on: ubuntu needs: release-tag-version - env: - CODEX_OAUTH: ${{ secrets.CODEX_OAUTH }} steps: - name: 測試工具 id: codex uses: https://gitea.jsc.idv.tw/composite-actions/codex@v${{ needs.release-tag-version.outputs.version }} with: + oauth: ${{ secrets.CODEX_OAUTH }} prompt: "請自我介紹" diff --git a/action.yml b/action.yml index 80abb0a..25df1ec 100644 --- a/action.yml +++ b/action.yml @@ -6,6 +6,9 @@ inputs: description: '傳給 Codex CLI 的提示詞' required: false default: "請自我介紹" + oauth: + description: 'base64 編碼的 Codex OAuth token 檔案內容' + required: true outputs: text: description: '輸出的文字' @@ -14,9 +17,11 @@ runs: using: 'composite' steps: - name: 安裝工具 + env: + OAUTH: ${{ inputs.oauth }} run: | - if [ -z "$CODEX_OAUTH" ]; then - echo 'CODEX_OAUTH environment variable is required (set it from secrets.CODEX_OAUTH in the caller workflow).' >&2 + if [ -z "$OAUTH" ]; then + echo 'oauth input (secrets.CODEX_OAUTH) is required and must not be empty.' >&2 exit 1 fi @@ -24,7 +29,7 @@ runs: oauth_file="$HOME/.codex/auth.json" install -d -m 700 "$(dirname "$oauth_file")" - printf '%s' "$CODEX_OAUTH" | base64 -d > "$oauth_file" + printf '%s' "$OAUTH" | base64 -d > "$oauth_file" chmod 600 "$oauth_file" shell: bash - name: 執行工具 -- 2.53.0 From 4077596fccc5237b4904b59e2db2adc213033c6d Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 05:58:47 +0000 Subject: [PATCH 12/15] refactor(codex): move email validation into main execution step and remove redundant check --- action.yml | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/action.yml b/action.yml index 25df1ec..f09fc6d 100644 --- a/action.yml +++ b/action.yml @@ -36,13 +36,22 @@ runs: id: codex env: MODEL: ${{ vars.CODEX_MODEL }} + EXPECTED_EMAIL: ${{ vars.CODEX_EMAIL }} PROMPT: ${{ inputs.prompt }} run: | if [ -z "$MODEL" ]; then echo 'CODEX_MODEL repository variable is required.' >&2 exit 1 fi - + if [ -z "$EXPECTED_EMAIL" ]; then + echo 'CODEX_EMAIL repository variable is required.' >&2 + exit 1 + fi + if [ -z "$PROMPT" ]; then + email="$(python3 "$GITHUB_ACTION_PATH/app/codex_account.py")" + echo "text=$email" >> "$GITHUB_OUTPUT" + exit 0 + fi text="$(codex exec --skip-git-repo-check -s danger-full-access --model "$MODEL" "$PROMPT")" printf '%s\n' "$text" { @@ -51,19 +60,6 @@ runs: echo 'CODEX_OUTPUT' } >> "$GITHUB_OUTPUT" shell: bash - - name: 驗證登入帳號 - env: - EXPECTED_EMAIL: ${{ vars.CODEX_EMAIL }} - run: | - if [ -z "$EXPECTED_EMAIL" ]; then - echo 'CODEX_EMAIL repository variable is required.' >&2 - exit 1 - fi - - email="$(python3 "$GITHUB_ACTION_PATH/app/codex_account.py")" - if [ "$email" != "$EXPECTED_EMAIL" ]; then - echo '登入帳號與 CODEX_EMAIL 不符' >&2 - exit 1 - fi - echo '登入帳號驗證通過' - shell: bash + - name: 檢查輸出 + if: ${{ steps.codex.outputs.text != vars.ANTIGRAVITY_EMAIL }} + run: exit 1 -- 2.53.0 From 03d082d0f3f074fa210f9ec658a09b88aeaa923c Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 14:09:23 +0800 Subject: [PATCH 13/15] =?UTF-8?q?refactor(codex):=20=E7=A7=BB=E9=99=A4=20a?= =?UTF-8?q?ction=20=E5=85=A7=E7=99=BB=E5=85=A5=E5=B8=B3=E8=99=9F=E9=A9=97?= =?UTF-8?q?=E8=AD=89=EF=BC=8C=E6=94=B9=E7=94=B1=E5=91=BC=E5=8F=AB=E7=AB=AF?= =?UTF-8?q?=E6=AA=A2=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/action.yml b/action.yml index f09fc6d..4a2de65 100644 --- a/action.yml +++ b/action.yml @@ -36,17 +36,12 @@ runs: id: codex env: MODEL: ${{ vars.CODEX_MODEL }} - EXPECTED_EMAIL: ${{ vars.CODEX_EMAIL }} PROMPT: ${{ inputs.prompt }} run: | if [ -z "$MODEL" ]; then echo 'CODEX_MODEL repository variable is required.' >&2 exit 1 fi - if [ -z "$EXPECTED_EMAIL" ]; then - echo 'CODEX_EMAIL repository variable is required.' >&2 - exit 1 - fi if [ -z "$PROMPT" ]; then email="$(python3 "$GITHUB_ACTION_PATH/app/codex_account.py")" echo "text=$email" >> "$GITHUB_OUTPUT" @@ -60,6 +55,3 @@ runs: echo 'CODEX_OUTPUT' } >> "$GITHUB_OUTPUT" shell: bash - - name: 檢查輸出 - if: ${{ steps.codex.outputs.text != vars.ANTIGRAVITY_EMAIL }} - run: exit 1 -- 2.53.0 From 0c8b0ad511aac6c1befbe7682022e1c030dbe002 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 06:11:06 +0000 Subject: [PATCH 14/15] fix(ci): add output check to validate response against expected email --- .gitea/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index d8d33d5..5c8b55f 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -30,3 +30,6 @@ jobs: with: oauth: ${{ secrets.CODEX_OAUTH }} prompt: "請自我介紹" + - name: 檢查輸出 + if: ${{ steps.codex.outputs.text != vars.CODEX_EMAIL }} + run: exit 1 -- 2.53.0 From b09237647627ec0a76213446985ec510186fcfc1 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 29 Jun 2026 06:12:07 +0000 Subject: [PATCH 15/15] refactor(codex): remove default prompt from inputs in action.yml --- .gitea/workflows/ci.yaml | 1 - action.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 5c8b55f..95aa463 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -29,7 +29,6 @@ jobs: uses: https://gitea.jsc.idv.tw/composite-actions/codex@v${{ needs.release-tag-version.outputs.version }} with: oauth: ${{ secrets.CODEX_OAUTH }} - prompt: "請自我介紹" - name: 檢查輸出 if: ${{ steps.codex.outputs.text != vars.CODEX_EMAIL }} run: exit 1 diff --git a/action.yml b/action.yml index 4a2de65..ef029ee 100644 --- a/action.yml +++ b/action.yml @@ -5,7 +5,6 @@ inputs: prompt: description: '傳給 Codex CLI 的提示詞' required: false - default: "請自我介紹" oauth: description: 'base64 編碼的 Codex OAuth token 檔案內容' required: true -- 2.53.0