@@ -13,15 +13,35 @@ description: |
1313 file with shape `{ taskType, correlationId, input }`, and passing
1414 its path in `task-spec-path`. Composers MUST NOT touch MoltNet
1515 creds.
16- 3. Wiring credentials through the explicit inputs below — those are
17- what this action owns.
16+ 3. Setting the MoltNet credential env vars at the **job** level
17+ (`env:` on the job, not as action inputs). This action reads them
18+ directly from the process env. Passing them through composite
19+ action `inputs:` round-trips multi-line secrets (notably
20+ `MOLTNET_GITHUB_APP_PRIVATE_KEY`) through GitHub Actions YAML
21+ expression substitution, which collapses newlines and produces an
22+ unparseable PEM — see issue #121 for the discovery.
23+
24+ Required job env:
25+ MOLTNET_AGENT_NAME, MOLTNET_IDENTITY_ID, MOLTNET_CLIENT_ID,
26+ MOLTNET_CLIENT_SECRET, MOLTNET_PUBLIC_KEY, MOLTNET_PRIVATE_KEY,
27+ MOLTNET_FINGERPRINT, MOLTNET_TEAM_ID, MOLTNET_DIARY_ID,
28+ MOLTNET_API_URL.
29+
30+ Optional job env (only if the agent uses `gh` from the VM):
31+ MOLTNET_GITHUB_APP_ID, MOLTNET_GITHUB_APP_INSTALLATION_ID,
32+ MOLTNET_GITHUB_APP_SLUG, MOLTNET_GITHUB_APP_PRIVATE_KEY.
33+
34+ Optional job env (provider-specific):
35+ OLLAMA_API_KEY (when provider=ollama),
36+ PI_AUTH_JSON (Pi/Codex auth dump, single-line JSON OK as input
37+ but kept here for symmetry).
1838
1939inputs :
2040 task-spec-path :
2141 description : |
2242 Path to a JSON file with shape `{ taskType, correlationId, input }`.
23- `teamId` and `diaryId` are taken from the action's inputs (which
24- mirror the agent's env ), not from the spec — composers are
43+ `teamId` and `diaryId` are taken from MoltNet env vars (which mirror
44+ the agent's config ), not from the spec — composers are
2545 credential-free by design.
2646 required : true
2747 skip-validation :
@@ -31,76 +51,13 @@ inputs:
3151 false.
3252 required : false
3353 default : ' false'
34- agent-name :
35- description : MoltNet agent name (used for `.moltnet/<agent>/` paths).
36- required : true
3754 provider :
3855 description : Agent runtime provider (e.g. `ollama`, `openai`).
3956 required : true
4057 model :
4158 description : Agent runtime model id.
4259 required : true
4360
44- # MoltNet credentials. Forwarded into the agent dir materialization step.
45- moltnet-identity-id :
46- description : MoltNet identity UUID.
47- required : true
48- moltnet-client-id :
49- description : OAuth client id.
50- required : true
51- moltnet-client-secret :
52- description : OAuth client secret.
53- required : true
54- moltnet-public-key :
55- description : Agent Ed25519 public key (base64 raw).
56- required : true
57- moltnet-private-key :
58- description : Agent Ed25519 private key (base64 raw).
59- required : true
60- moltnet-fingerprint :
61- description : Agent fingerprint.
62- required : true
63- moltnet-team-id :
64- description : Team UUID.
65- required : true
66- moltnet-diary-id :
67- description : Diary UUID.
68- required : true
69- moltnet-api-url :
70- description : MoltNet API base URL.
71- required : true
72-
73- # GitHub App credentials for the agent's gh calls (optional — required if
74- # the imposer or the task itself uses `gh`).
75- moltnet-github-app-id :
76- description : GitHub App id.
77- required : false
78- default : ' '
79- moltnet-github-app-installation-id :
80- description : GitHub App installation id.
81- required : false
82- default : ' '
83- moltnet-github-app-slug :
84- description : GitHub App slug.
85- required : false
86- default : ' '
87- moltnet-github-app-private-key :
88- description : GitHub App private key (PEM).
89- required : false
90- default : ' '
91-
92- # Provider-specific secrets.
93- ollama-api-key :
94- description : Ollama API key (required when provider=ollama).
95- required : false
96- default : ' '
97- pi-auth-json :
98- description : |
99- Contents of `~/.pi/auth.json` for Codex/Pi providers. Optional — if
100- absent, Pi falls back to env-var providers.
101- required : false
102- default : ' '
103-
10461runs :
10562 using : composite
10663 steps :
@@ -113,23 +70,9 @@ runs:
11370
11471 - name : Materialize MoltNet agent dir from env
11572 shell : bash
116- env :
117- MOLTNET_AGENT_NAME : ${{ inputs.agent-name }}
118- MOLTNET_IDENTITY_ID : ${{ inputs.moltnet-identity-id }}
119- MOLTNET_CLIENT_ID : ${{ inputs.moltnet-client-id }}
120- MOLTNET_CLIENT_SECRET : ${{ inputs.moltnet-client-secret }}
121- MOLTNET_PUBLIC_KEY : ${{ inputs.moltnet-public-key }}
122- MOLTNET_PRIVATE_KEY : ${{ inputs.moltnet-private-key }}
123- MOLTNET_FINGERPRINT : ${{ inputs.moltnet-fingerprint }}
124- MOLTNET_TEAM_ID : ${{ inputs.moltnet-team-id }}
125- MOLTNET_DIARY_ID : ${{ inputs.moltnet-diary-id }}
126- MOLTNET_API_URL : ${{ inputs.moltnet-api-url }}
127- MOLTNET_GITHUB_APP_ID : ${{ inputs.moltnet-github-app-id }}
128- MOLTNET_GITHUB_APP_INSTALLATION_ID : ${{ inputs.moltnet-github-app-installation-id }}
129- MOLTNET_GITHUB_APP_SLUG : ${{ inputs.moltnet-github-app-slug }}
130- MOLTNET_GITHUB_APP_PRIVATE_KEY : ${{ inputs.moltnet-github-app-private-key }}
13173 run : |
13274 set -euo pipefail
75+ : "${MOLTNET_AGENT_NAME:?MOLTNET_AGENT_NAME must be set at the job level}"
13376 AGENT_DIR="$GITHUB_WORKSPACE/.moltnet/$MOLTNET_AGENT_NAME"
13477 # Idempotent: a caller workflow that needs the agent dir earlier
13578 # (e.g. to run an imposer script) may already have materialized it.
@@ -141,13 +84,32 @@ runs:
14184 {
14285 echo "GIT_CONFIG_GLOBAL=$AGENT_DIR/gitconfig"
14386 echo "MOLTNET_AGENT_DIR=$AGENT_DIR"
144- echo "MOLTNET_AGENT_NAME=$MOLTNET_AGENT_NAME"
14587 } >> "$GITHUB_ENV"
14688
89+ - name : Verify GitHub App PEM is well-formed
90+ shell : bash
91+ run : |
92+ set -euo pipefail
93+ # `config init-from-env` writes the PEM at <agent>.pem when the
94+ # GitHub App secrets are present. Skip the check if the file is
95+ # absent (the agent will just not call `gh`).
96+ PEM="$MOLTNET_AGENT_DIR/$MOLTNET_AGENT_NAME.pem"
97+ if [ ! -f "$PEM" ]; then
98+ echo "::notice::No GitHub App PEM at $PEM — agent gh calls will fall back."
99+ exit 0
100+ fi
101+ if ! head -1 "$PEM" | grep -q "^-----BEGIN .*PRIVATE KEY-----$"; then
102+ echo "::error::GitHub App PEM at $PEM is not a valid PEM — first line is not a BEGIN header. This usually means MOLTNET_GITHUB_APP_PRIVATE_KEY was passed through a composite-action input, which collapses newlines. Set it as a JOB env var instead."
103+ exit 1
104+ fi
105+ if ! tail -1 "$PEM" | grep -q "^-----END .*PRIVATE KEY-----$"; then
106+ echo "::error::GitHub App PEM at $PEM is not a valid PEM — last line is not an END footer."
107+ exit 1
108+ fi
109+ echo "::notice::GitHub App PEM at $PEM looks well-formed."
110+
147111 - name : Materialize Pi auth.json
148112 shell : bash
149- env :
150- PI_AUTH_JSON : ${{ inputs.pi-auth-json }}
151113 run : |
152114 set -euo pipefail
153115 if [ -n "${PI_AUTH_JSON:-}" ]; then
@@ -200,10 +162,6 @@ runs:
200162 env :
201163 TASK_SPEC_PATH : ${{ inputs.task-spec-path }}
202164 SKIP_VALIDATION : ${{ inputs.skip-validation }}
203- MOLTNET_AGENT_NAME : ${{ inputs.agent-name }}
204- MOLTNET_TEAM_ID : ${{ inputs.moltnet-team-id }}
205- MOLTNET_DIARY_ID : ${{ inputs.moltnet-diary-id }}
206- MOLTNET_API_URL : ${{ inputs.moltnet-api-url }}
207165 run : |
208166 set -euo pipefail
209167 if [ ! -f "$TASK_SPEC_PATH" ]; then
@@ -253,10 +211,8 @@ runs:
253211 shell : bash
254212 env :
255213 TASK_ID : ${{ steps.create-task.outputs.task-id }}
256- MOLTNET_AGENT_NAME : ${{ inputs.agent-name }}
257214 MOLTNET_AGENT_PROVIDER : ${{ inputs.provider }}
258215 MOLTNET_AGENT_MODEL : ${{ inputs.model }}
259- OLLAMA_API_KEY : ${{ inputs.ollama-api-key }}
260216 run : |
261217 set -euo pipefail
262218 if [ -z "$TASK_ID" ]; then
@@ -276,7 +232,7 @@ runs:
276232 PI_AGENT_DIR="${PI_CODING_AGENT_DIR:-$RUNNER_TEMP/.pi/agent}"
277233 if [ "$PROVIDER" = "ollama" ]; then
278234 if [ -z "${OLLAMA_API_KEY:-}" ]; then
279- echo "::error::ollama-api-key input is required when provider=ollama" >&2
235+ echo "::error::OLLAMA_API_KEY env var is required when provider=ollama" >&2
280236 exit 1
281237 fi
282238 export PI_CODING_AGENT_DIR="$PI_AGENT_DIR"
0 commit comments