openai/codex-action

Public

mirrored from https://github.com/openai/codex-actionAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
pr10

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

action.yml

222lines · modecode

1name: "Codex Exec Action"
2description: "Run `codex exec` with a prompt."
3author: "OpenAI"
4inputs:
5 prompt:
6 description: "Prompt to pass to Codex. `prompt` or `prompt-file` must be provided."
7 required: false
8 default: ""
9 prompt-file:
10 description: "Path to file that contains the prompt to pass to Codex. `prompt` or `prompt-file` must be provided."
11 required: false
12 default: ""
13 output-file:
14 description: "File where the final Codex message is written. Leave empty to skip writing a file."
15 required: false
16 default: ""
17 openai-api-key:
18 description: "OpenAI API key used by Codex."
19 required: true
20 working-directory:
21 description: "Working directory that Codex should use. Defaults to the repository root."
22 required: false
23 default: ""
24 sandbox:
25 description: |
26 Sandbox mode for Codex. One of `workspace-write` (default), `read-only` or `danger-full-access`.
27 required: false
28 default: "workspace-write"
29 codex-version:
30 description: "Version of `@openai/codex` to install."
31 required: false
32 default: "0.43.0-alpha.17"
33 codex-args:
34 description: "Additional args to pass through to `codex exec`. If this value starts with `[`, it will be parsed as a JSON array; otherwise, it will be parsed as a shell-like string."
35 required: false
36 default: ""
37 output-schema:
38 description: "Inline schema contents to use with `codex exec --output-schema`."
39 required: false
40 default: ""
41 output-schema-file:
42 description: "File path to the schema that should be passed to `codex exec --output-schema`."
43 required: false
44 default: ""
45 model:
46 description: "Model the agent should use."
47 required: false
48 default: ""
49 codex-home:
50 description: "Directory to use as the Codex home directory. If empty, the default Codex home directory will be used."
51 required: false
52 default: ""
53 safety-strategy:
54 description: |
55 Specify one of the following options (on Windows, the only supported option is `unsafe`):
56
57 * `drop-sudo` (default, IRREVERSIBLE) Drop sudo privileges (if any) from
58 the default user before running Codex, and run Codex as that user. This
59 is only supported on Linux and macOS runners. This option is
60 irreversible: if the default user has sudo privileges, they will be
61 removed permanently for the duration of the job.
62 * `unprivileged-user` Run Codex as the specified user specified by the
63 `codex-user` option (the user must already exist). Note the caller is
64 responsible for ensuring the specified user has the privileges it needs
65 to perform the requested actions. For example, the copy of the repo
66 created by `actions/checkout` is not world-readable by default.
67 * `read-only` Run Codex in a sandbox that can read any file on disk,
68 but cannot write to disk or access the network. Note Codex will still
69 run as the default user for this Action, which likely has sudo
70 privileges, so it could read `openai-api-key` from memory and reveal it
71 by printing it to the output of the GitHub Action.
72 * `unsafe` (NOT RECOMMENDED) Do not try to restrict Codex's privileges at all.
73 This is extremely dangerous, as the default user for this Action likely
74 has sudo privileges, which means it can read secrets stored in memory
75 (such as the value of `openai-api-key`) and print them to the output
76 of the GitHub Action or exfiltrate them in other ways.
77 required: false
78 default: "drop-sudo"
79 codex-user:
80 description: "If `safety-strategy` is set to `unprivileged-user`, this specifies the UNIX username to run Codex as."
81 required: false
82 default: ""
83 require-repo-write:
84 description: "Whether to require the triggering actor to have write access to the repository before running."
85 required: false
86 default: "true"
87 allow-bots:
88 description: "Allow runs triggered by GitHub Apps/bot accounts to bypass the write-access check."
89 required: false
90 default: "false"
91outputs:
92 final-message:
93 description: "Raw output emitted by `codex exec`."
94 value: ${{ steps.run_codex.outputs['final-message'] }}
95runs:
96 using: "composite"
97 steps:
98 - name: Validate Windows safety strategy
99 if: ${{ runner.os == 'Windows' }}
100 shell: bash
101 run: |
102 if [ "${{ inputs['safety-strategy'] }}" != "unsafe" ]; then
103 echo "On Windows, inputs['safety-strategy'] must be 'unsafe'" >&2
104 echo "because no viable sandboxing options are available at this time." >&2
105 exit 1
106 fi
107
108 - name: Ensure Node.js available
109 uses: actions/setup-node@v4
110 with:
111 node-version: "20"
112
113 - name: Check repository write access
114 if: ${{ inputs['require-repo-write'] == 'true' }}
115 env:
116 ALLOW_BOTS: ${{ inputs['allow-bots'] }}
117 GITHUB_TOKEN: ${{ github.token }}
118 shell: bash
119 run: |
120 node "${{ github.action_path }}/dist/main.js" check-write-access --allow-bots "$ALLOW_BOTS"
121
122 - name: Install Codex CLI
123 shell: bash
124 run: npm install -g "@openai/codex@${{ inputs['codex-version'] }}"
125
126 - name: Install Codex Responses API proxy
127 shell: bash
128 run: npm install -g "@openai/codex-responses-api-proxy@${{ inputs['codex-version'] }}"
129
130 - name: Start Responses API proxy
131 id: start_proxy
132 env:
133 OPENAI_API_KEY: ${{ inputs['openai-api-key'] }}
134 shell: bash
135 run: |
136 tmpfile=$(mktemp)
137 (
138 printenv OPENAI_API_KEY | codex-responses-api-proxy --http-shutdown --server-info "$tmpfile"
139 ) &
140 for _ in {1..10}; do
141 if [ -s "$tmpfile" ]; then
142 break
143 fi
144 sleep 1
145 done
146 if [ ! -s "$tmpfile" ]; then
147 echo "responses-api-proxy did not write server info" >&2
148 exit 1
149 fi
150 echo "server_info_file=$tmpfile" >> "$GITHUB_OUTPUT"
151
152 # This step has an output named `port`.
153 - name: Read server info
154 id: read_server_info
155 shell: bash
156 run: node "${{ github.action_path }}/dist/main.js" read-server-info "${{ steps.start_proxy.outputs.server_info_file }}"
157
158 - name: Drop sudo privilege, if appropriate
159 if: ${{ inputs['safety-strategy'] == 'drop-sudo' }}
160 shell: bash
161 run: |
162 case "${RUNNER_OS}" in
163 Linux)
164 node "${{ github.action_path }}/dist/main.js" drop-sudo --user runner --group sudo
165 ;;
166 macOS)
167 node "${{ github.action_path }}/dist/main.js" drop-sudo --user runner --group admin
168 ;;
169 *)
170 echo "Unsupported OS for drop-sudo: ${RUNNER_OS}" >&2
171 exit 1
172 ;;
173 esac
174
175 - name: Verify sudo privilege removed
176 if: ${{ inputs['safety-strategy'] == 'drop-sudo' }}
177 shell: bash
178 run: |
179 if sudo -n true 2>/dev/null; then
180 echo "Expected sudo to be disabled, but sudo succeeded." >&2
181 exit 1
182 fi
183 echo "Confirmed sudo privilege is disabled."
184
185 - name: Run codex exec
186 id: run_codex
187 env:
188 CODEX_PROMPT: ${{ inputs.prompt }}
189 CODEX_PROMPT_FILE: ${{ inputs['prompt-file'] }}
190 CODEX_OUTPUT_FILE: ${{ inputs['output-file'] }}
191 CODEX_HOME: ${{ inputs['codex-home'] }}
192 CODEX_WORKING_DIRECTORY: ${{ inputs['working-directory'] || github.workspace }}
193 CODEX_SANDBOX: ${{ inputs.sandbox }}
194 CODEX_ARGS: ${{ inputs['codex-args'] }}
195 CODEX_OUTPUT_SCHEMA: ${{ inputs['output-schema'] }}
196 CODEX_OUTPUT_SCHEMA_FILE: ${{ inputs['output-schema-file'] }}
197 CODEX_MODEL: ${{ inputs.model }}
198 CODEX_SAFETY_STRATEGY: ${{ inputs['safety-strategy'] }}
199 CODEX_USER: ${{ inputs['codex-user'] }}
200 FORCE_COLOR: 1
201 shell: bash
202 run: |
203 node "${{ github.action_path }}/dist/main.js" run-codex-exec \
204 --prompt "${CODEX_PROMPT}" \
205 --prompt-file "${CODEX_PROMPT_FILE}" \
206 --output-file "$CODEX_OUTPUT_FILE" \
207 --codex-home "$CODEX_HOME" \
208 --cd "$CODEX_WORKING_DIRECTORY" \
209 --proxy-port "${{ steps.read_server_info.outputs.port }}" \
210 --extra-args "$CODEX_ARGS" \
211 --output-schema "$CODEX_OUTPUT_SCHEMA" \
212 --output-schema-file "$CODEX_OUTPUT_SCHEMA_FILE" \
213 --sandbox "$CODEX_SANDBOX" \
214 --model "$CODEX_MODEL" \
215 --safety-strategy "$CODEX_SAFETY_STRATEGY" \
216 --codex-user "$CODEX_USER"
217
218 - name: Shutdown codex webserver
219 env:
220 CODEX_SERVER_PORT: ${{ steps.read_server_info.outputs.port }}
221 shell: bash
222 run: curl --fail --silent --show-error "http://127.0.0.1:${CODEX_SERVER_PORT}/shutdown"
223