Spaces:
Sleeping
Sleeping
Load Codespaces secrets before starting the server
Browse filesA codespace came up serving nothing. The image was fine and the hook did run, but
the log was empty and OPENCODE_SERVER_PASSWORD was absent from the environment.
Codespaces secrets are not passed to postStartCommand. They are written to
/workspaces/.codespaces/shared/user-secrets-envs.json and applied to interactive
shells, so a server started by a lifecycle hook sees none of them — and
entrypoint.sh then refuses to run, exactly as it should, leaving a public port
with nothing behind it.
start-opencode.sh reads that file first, without overriding anything
devcontainer.json set explicitly, and says so plainly when the password is still
missing rather than failing silently.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
.devcontainer/devcontainer.json
CHANGED
|
@@ -53,12 +53,12 @@
|
|
| 53 |
},
|
| 54 |
|
| 55 |
// Runs on create *and* on every resume from an idle stop, which is what makes the codespace
|
| 56 |
-
// behave like a server rather than a dev box you have to
|
| 57 |
-
//
|
| 58 |
-
//
|
| 59 |
-
//
|
| 60 |
-
//
|
| 61 |
-
"postStartCommand": "setsid nohup /
|
| 62 |
|
| 63 |
"customizations": {
|
| 64 |
"vscode": {
|
|
|
|
| 53 |
},
|
| 54 |
|
| 55 |
// Runs on create *and* on every resume from an idle stop, which is what makes the codespace
|
| 56 |
+
// behave like a server rather than a dev box you have to restart by hand.
|
| 57 |
+
//
|
| 58 |
+
// It goes through start-opencode.sh rather than straight to the entrypoint because
|
| 59 |
+
// Codespaces secrets are not in this hook's environment — see that script. setsid detaches
|
| 60 |
+
// the server from the shell, which exits as soon as the hook returns.
|
| 61 |
+
"postStartCommand": "setsid nohup ${containerWorkspaceFolder}/.devcontainer/start-opencode.sh > /tmp/opencode.log 2>&1 < /dev/null & echo started",
|
| 62 |
|
| 63 |
"customizations": {
|
| 64 |
"vscode": {
|
.devcontainer/start-opencode.sh
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Boot the opencode server inside a GitHub Codespace.
|
| 3 |
+
#
|
| 4 |
+
# This exists for one reason: Codespaces secrets are not in postStartCommand's environment.
|
| 5 |
+
# They are written to a JSON file and applied to interactive shells, so a server started by
|
| 6 |
+
# the lifecycle hook sees none of them — including OPENCODE_SERVER_PASSWORD, without which
|
| 7 |
+
# entrypoint.sh correctly refuses to run and the codespace comes up serving nothing.
|
| 8 |
+
#
|
| 9 |
+
# Sourcing that file first is what makes the codespace behave like the Space and the Railway
|
| 10 |
+
# service, where the platform hands the process its variables directly.
|
| 11 |
+
set -euo pipefail
|
| 12 |
+
|
| 13 |
+
SECRETS="/workspaces/.codespaces/shared/user-secrets-envs.json"
|
| 14 |
+
|
| 15 |
+
if [ -f "$SECRETS" ]; then
|
| 16 |
+
# A flat { "NAME": "value" } object. Exported only if not already set, so a variable given
|
| 17 |
+
# explicitly by devcontainer.json still wins.
|
| 18 |
+
while IFS='=' read -r name value; do
|
| 19 |
+
[ -n "$name" ] || continue
|
| 20 |
+
if [ -z "${!name:-}" ]; then
|
| 21 |
+
export "$name=$value"
|
| 22 |
+
fi
|
| 23 |
+
done < <(python3 -c '
|
| 24 |
+
import json, sys
|
| 25 |
+
with open(sys.argv[1]) as handle:
|
| 26 |
+
for name, value in json.load(handle).items():
|
| 27 |
+
if isinstance(value, str) and "\n" not in value:
|
| 28 |
+
print(f"{name}={value}")
|
| 29 |
+
' "$SECRETS")
|
| 30 |
+
echo "codespaces: loaded secrets from $(basename "$SECRETS")"
|
| 31 |
+
else
|
| 32 |
+
echo "codespaces: no secrets file at $SECRETS"
|
| 33 |
+
fi
|
| 34 |
+
|
| 35 |
+
if [ -z "${OPENCODE_SERVER_PASSWORD:-}" ]; then
|
| 36 |
+
echo "codespaces: OPENCODE_SERVER_PASSWORD is still unset after loading secrets." >&2
|
| 37 |
+
echo " Set it as a Codespaces secret, not a repository or Actions secret:" >&2
|
| 38 |
+
echo " gh secret set OPENCODE_SERVER_PASSWORD --app codespaces --repo OWNER/REPO" >&2
|
| 39 |
+
fi
|
| 40 |
+
|
| 41 |
+
exec /home/node/entrypoint.sh
|