From 5e8097dd071b66c007f033f8f4edebd2c1118258 Mon Sep 17 00:00:00 2001 From: viyatb-oai Date: Mon, 16 Mar 2026 22:24:17 -0700 Subject: [PATCH 1/4] fix: enable bubblewrap user namespaces on GitHub Linux --- README.md | 1 + action.yml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 7560878..a8a604b 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ See [Protecting your `OPENAI_API_KEY`](./docs/security.md#protecting-your-openai - **Windows**: GitHub-hosted Windows runners lack a supported sandbox. Set `safety-strategy: unsafe`. The action validates this and exits early otherwise. - **Linux/macOS**: All options for `safety-strategy` are supported. Again, if you pick `drop-sudo`, remember that later steps in your `job` that rely on `sudo` will fail. If you do need to run code that requires `sudo` after `openai/codex-action` has run, one option is to pipe the output of `openai/codex-action` to a fresh `job` on a new host and to continue your workflow from there. +- **GitHub-hosted Linux runners**: When `sandbox` is not `danger-full-access`, the action enables unprivileged user namespaces during setup and clears Ubuntu's AppArmor gate when present. This avoids the `bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted` failure seen on newer hosted images, including workflows that use the action once to bootstrap Codex and then call `codex` in later steps. Self-hosted Linux runners still need equivalent kernel support configured ahead of time. ## Outputs diff --git a/action.yml b/action.yml index c1cb84f..82a24e4 100644 --- a/action.yml +++ b/action.yml @@ -259,6 +259,22 @@ runs: --port "$PROXY_PORT" \ --safety-strategy "$SAFETY_STRATEGY" + - name: Enable Linux user namespaces for bubblewrap + if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' && inputs.sandbox != 'danger-full-access' && (inputs['openai-api-key'] != '' || inputs.prompt != '' || inputs['prompt-file'] != '') }} + shell: bash + run: | + current_userns="$(sysctl -n kernel.unprivileged_userns_clone 2>/dev/null || true)" + if [ -n "$current_userns" ] && [ "$current_userns" != "1" ]; then + echo "Enabling kernel.unprivileged_userns_clone for bubblewrap." + sudo sysctl -w kernel.unprivileged_userns_clone=1 + fi + + current_apparmor="$(sysctl -n kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || true)" + if [ -n "$current_apparmor" ] && [ "$current_apparmor" != "0" ]; then + echo "Disabling kernel.apparmor_restrict_unprivileged_userns for bubblewrap." + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 + fi + - name: Drop sudo privilege, if appropriate if: ${{ inputs['safety-strategy'] == 'drop-sudo' && inputs['openai-api-key'] != '' }} shell: bash From cce996ac9fa4df3e877551b697763d90fdf60765 Mon Sep 17 00:00:00 2001 From: viyatb-oai Date: Mon, 16 Mar 2026 22:37:26 -0700 Subject: [PATCH 2/4] fix: apply Linux userns setup for all sandbox modes --- README.md | 2 +- action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8a604b..ce266a8 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ See [Protecting your `OPENAI_API_KEY`](./docs/security.md#protecting-your-openai - **Windows**: GitHub-hosted Windows runners lack a supported sandbox. Set `safety-strategy: unsafe`. The action validates this and exits early otherwise. - **Linux/macOS**: All options for `safety-strategy` are supported. Again, if you pick `drop-sudo`, remember that later steps in your `job` that rely on `sudo` will fail. If you do need to run code that requires `sudo` after `openai/codex-action` has run, one option is to pipe the output of `openai/codex-action` to a fresh `job` on a new host and to continue your workflow from there. -- **GitHub-hosted Linux runners**: When `sandbox` is not `danger-full-access`, the action enables unprivileged user namespaces during setup and clears Ubuntu's AppArmor gate when present. This avoids the `bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted` failure seen on newer hosted images, including workflows that use the action once to bootstrap Codex and then call `codex` in later steps. Self-hosted Linux runners still need equivalent kernel support configured ahead of time. +- **GitHub-hosted Linux runners**: The action enables unprivileged user namespaces during setup and clears Ubuntu's AppArmor gate when present. This avoids the `bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted` failure seen on newer hosted images, including workflows that use the action once to bootstrap Codex and then call `codex` in later steps. Self-hosted Linux runners still need equivalent kernel support configured ahead of time. ## Outputs diff --git a/action.yml b/action.yml index 82a24e4..07d575c 100644 --- a/action.yml +++ b/action.yml @@ -260,7 +260,7 @@ runs: --safety-strategy "$SAFETY_STRATEGY" - name: Enable Linux user namespaces for bubblewrap - if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' && inputs.sandbox != 'danger-full-access' && (inputs['openai-api-key'] != '' || inputs.prompt != '' || inputs['prompt-file'] != '') }} + if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' && (inputs['openai-api-key'] != '' || inputs.prompt != '' || inputs['prompt-file'] != '') }} shell: bash run: | current_userns="$(sysctl -n kernel.unprivileged_userns_clone 2>/dev/null || true)" From 4e14672719ccccdfa667213f19e7c0fae9876ce1 Mon Sep 17 00:00:00 2001 From: viyatb-oai Date: Mon, 16 Mar 2026 22:55:10 -0700 Subject: [PATCH 3/4] fix: document Linux bubblewrap setup invariants --- action.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/action.yml b/action.yml index 07d575c..8d89c88 100644 --- a/action.yml +++ b/action.yml @@ -263,12 +263,21 @@ runs: if: ${{ runner.os == 'Linux' && runner.environment == 'github-hosted' && (inputs['openai-api-key'] != '' || inputs.prompt != '' || inputs['prompt-file'] != '') }} shell: bash run: | + set -euo pipefail + + # Bubblewrap needs unprivileged user namespaces on GitHub-hosted Linux + # runners. This step runs before drop-sudo, then becomes a no-op on + # later codex-action invocations in the same job because the sysctls + # already have the desired values. current_userns="$(sysctl -n kernel.unprivileged_userns_clone 2>/dev/null || true)" if [ -n "$current_userns" ] && [ "$current_userns" != "1" ]; then echo "Enabling kernel.unprivileged_userns_clone for bubblewrap." sudo sysctl -w kernel.unprivileged_userns_clone=1 fi + # Ubuntu 24.04+ can additionally block unprivileged user namespaces via + # AppArmor, which causes bubblewrap to fail with + # `loopback: Failed RTM_NEWADDR: Operation not permitted`. current_apparmor="$(sysctl -n kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || true)" if [ -n "$current_apparmor" ] && [ "$current_apparmor" != "0" ]; then echo "Disabling kernel.apparmor_restrict_unprivileged_userns for bubblewrap." From beaf98fba48521d20a4949ae9e3f3895cf8a0a87 Mon Sep 17 00:00:00 2001 From: viyatb-oai Date: Mon, 16 Mar 2026 22:55:49 -0700 Subject: [PATCH 4/4] fix: link Linux bubblewrap workaround context --- action.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 8d89c88..ab4edf2 100644 --- a/action.yml +++ b/action.yml @@ -268,7 +268,8 @@ runs: # Bubblewrap needs unprivileged user namespaces on GitHub-hosted Linux # runners. This step runs before drop-sudo, then becomes a no-op on # later codex-action invocations in the same job because the sysctls - # already have the desired values. + # already have the desired values. See issue #75 for the failure mode + # this is working around on newer Ubuntu images. current_userns="$(sysctl -n kernel.unprivileged_userns_clone 2>/dev/null || true)" if [ -n "$current_userns" ] && [ "$current_userns" != "1" ]; then echo "Enabling kernel.unprivileged_userns_clone for bubblewrap."