@andrian.yablonskyy/thub-agent 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -56,7 +56,7 @@ Key options for `thub run`:
56
56
  | `--git-repo <url> [<branch>\|<tag>\|<commit>]` | A git repository the Client clones (default ref: the default branch); the command runs in the checkout. |
57
57
  | `--depth <n>` | With `--git-repo`: commits to fetch, default `1`; `0` = full history. |
58
58
  | `--git-options <string>` | With `--git-repo`: extra git options placed between `git` and its subcommand on the Client, e.g. `'-c core.sshCommand="ssh -i ~/.ssh/lab_key -p 2222"'`. Shell-quoted (no shell run). Stored with the job, so reference key files rather than inlining secrets. |
59
- | `--env <vars>` | Environment variables for every command the Client runs for the job (git, docker login, `--command`): `NAME=value[,NAME=value]`, repeatable; `--env NAME` alone takes the value from your shell. `DOCKER_REGISTRY` + `DOCKER_USERNAME` + `DOCKER_PASSWORD`: the Client logs in to that registry first (`docker login … --password-stdin`). Values reach only the Client running the job; the Coordinator masks them and drops them when the job ends. |
59
+ | `--env <vars>` | Environment variables for every command the Client runs for the job (git and `--command`): `NAME=value[,NAME=value]`, repeatable; `--env NAME` alone takes the value from your shell. Any names — none means anything to the Agent or the Client (only `THUB_*`, `GIT_TERMINAL_PROMPT`, `GIT_ALLOW_PROTOCOL` are refused). Every value is a secret: it reaches only the Client running the job; the Coordinator masks it and drops it when the job ends. |
60
60
  | `--suite <name>` | Passed to the command as `THUB_SUITE`. |
61
61
  | `--arg <value>` | Extra argument for the command, as `"$@"` (repeatable). |
62
62
  | `--timeout <dur>` | e.g. `30m`, default `30m`. |
@@ -135,7 +135,7 @@ thub run --type hw --board nucleo-f401re \
135
135
 
136
136
  ## Environment variables and secrets
137
137
 
138
- `--env NAME=value[,NAME=value]` (repeatable) sets variables for every command the Client runs for the job: git, the registry login, the DUT setup and `--command`. `--env NAME` alone takes the value from your own environment, so a secret stays off the command line and out of CI logs:
138
+ `--env NAME=value[,NAME=value]` (repeatable) sets variables for every command the Client runs for the job: git and `--command`. The names are yours; none means anything to the Agent or the Client. `--env NAME` alone takes the value from your own environment, so a secret stays off the command line and out of CI logs:
139
139
 
140
140
  ```bash
141
141
  export API_TOKEN=…
@@ -149,21 +149,28 @@ thub run --type sw --git-repo "$TESTS_REPO" \
149
149
  - They reach **only the Client that runs the job**.
150
150
  - The Agent API shows every value as `***`: `thub status --json`, `thub jobs --json`, even for your own job. The dashboard lists the names only.
151
151
  - The Coordinator replaces the values with `***` once the job ends.
152
- - A `--dry-run` masks values whose names look secret (`*PASS*`, `*TOKEN*`, `*KEY*`, …).
152
+ - A `--dry-run` shows every value as `***`, whatever its name.
153
153
 
154
154
  Your command's output is the job's log, so don't print secrets. Everything else — `--command`, `--arg`, `--meta`, `--git-options` — is stored as is and visible, so never put secrets there.
155
155
 
156
156
  ## Docker
157
157
 
158
- **Log in to a custom registry:** pass `DOCKER_REGISTRY`, `DOCKER_USERNAME` and `DOCKER_PASSWORD` with `--env`. Before anything else, the Client runs `echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USERNAME" --password-stdin` into a Docker config of the job's own. The job's commands get it as `DOCKER_CONFIG`, and it's deleted with the job.
159
-
160
- **Pull an image from it as the DUT:**
158
+ **Log in to a custom registry:** in `--command`, with credentials passed as `--env` under any names. Point `DOCKER_CONFIG` at the job's work directory first, so the login is deleted with the job rather than left in the Client user's `~/.docker` for later jobs:
161
159
 
162
160
  ```bash
163
161
  export DOCKER_PASSWORD=…
164
- thub run --type sw \
165
- --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USERNAME=ci --env DOCKER_PASSWORD \
166
- --docker-image registry.lab.local:5000/dut-emulator:2026.08 \
162
+ thub run --type hw \
163
+ --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USER=ci --env DOCKER_PASSWORD \
164
+ --command 'export DOCKER_CONFIG="$THUB_WORK_DIR/.docker" &&
165
+ echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USER" --password-stdin &&
166
+ docker pull "$DOCKER_REGISTRY/team/test-runner:1.4"' \
167
+ --wait
168
+ ```
169
+
170
+ **Pull an image as the DUT:** `--docker-image` is pulled by the Client before the command runs, as its service user. For a private registry, log in once on the Client host as that user: `sudo -u thub docker login registry.lab.local:5000`.
171
+
172
+ ```bash
173
+ thub run --type sw --docker-image registry.lab.local:5000/dut-emulator:2026.08 \
167
174
  --git-repo "$TESTS_REPO" --command './ci/test.sh --dut "$THUB_DUT_HOST"' --wait
168
175
  ```
169
176
 
@@ -171,10 +178,12 @@ thub run --type sw \
171
178
 
172
179
  ```bash
173
180
  thub run --type sw \
174
- --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USERNAME=ci --env DOCKER_PASSWORD \
181
+ --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USER=ci --env DOCKER_PASSWORD \
175
182
  --git-repo git@bitbucket.org:yourorg/web-ui-tests.git main \
176
183
  --git-options '-c core.sshCommand="ssh -i /home/thub/.ssh/id_ed25519 -o StrictHostKeyChecking=accept-new"' \
177
- --command 'docker run --rm -v "$THUB_WORK_DIR:/work" -w /work "$DOCKER_REGISTRY/python:3.14" ./run-tests.sh' \
184
+ --command 'export DOCKER_CONFIG="$THUB_WORK_DIR/.docker" &&
185
+ echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USER" --password-stdin &&
186
+ docker run --rm -v "$THUB_WORK_DIR:/work" -w /work "$DOCKER_REGISTRY/python:3.14" ./run-tests.sh' \
178
187
  --wait
179
188
  ```
180
189
 
@@ -182,17 +191,19 @@ thub run --type sw \
182
191
 
183
192
  ```bash
184
193
  thub run --type sw \
185
- --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USERNAME=ci --env DOCKER_PASSWORD \
194
+ --env DOCKER_REGISTRY=registry.lab.local:5000,DOCKER_USER=ci --env DOCKER_PASSWORD \
186
195
  --env TEST_IMAGE=registry.lab.local:5000/team/test-runner:1.4 \
187
196
  --env REPO_URL=git@bitbucket.org:yourorg/web-ui-tests.git,REPO_REF=main \
188
197
  --env 'GIT_SSH_COMMAND=ssh -i /root/.ssh/id_ed25519 -o StrictHostKeyChecking=accept-new' \
189
- --command 'docker run --rm -e REPO_URL -e REPO_REF -e GIT_SSH_COMMAND \
198
+ --command 'export DOCKER_CONFIG="$THUB_WORK_DIR/.docker" &&
199
+ echo "$DOCKER_PASSWORD" | docker login "$DOCKER_REGISTRY" --username "$DOCKER_USER" --password-stdin &&
200
+ docker run --rm -e REPO_URL -e REPO_REF -e GIT_SSH_COMMAND \
190
201
  -v "$HOME/.ssh:/root/.ssh:ro" -v "$THUB_WORK_DIR/results:/results" \
191
202
  "$TEST_IMAGE" sh -c "git clone --depth 1 --branch \"\$REPO_REF\" \"\$REPO_URL\" /src && cd /src && ./run-tests.sh --junit /results"' \
192
203
  --wait
193
204
  ```
194
205
 
195
- The Client host needs Docker and the Client's user in the `docker` group; SW Clients have both. Add `--dry-run` to see every command a job would run on the Client (secret-looking values masked) without running any. More in the main README, §7.2.
206
+ The Client host needs Docker and the Client's user in the `docker` group; SW Clients have both. Add `--dry-run` to see every command a job would run on the Client (every `--env` value shown as `***`) without running any. More in the main README, §7.2.
196
207
 
197
208
  ## Job status and PASS/FAIL
198
209
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrian.yablonskyy/thub-agent",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "TestHub Agent CLI — the single entry point CI/CD and developers use to submit and follow test jobs",
5
5
  "bin": {
6
6
  "thub": "./src/cli.js"
@@ -12,7 +12,7 @@
12
12
  "lint:fix": "eslint . --fix"
13
13
  },
14
14
  "dependencies": {
15
- "@andrian.yablonskyy/thub-common": "^1.0.28",
15
+ "@andrian.yablonskyy/thub-common": "^1.0.30",
16
16
  "commander": "^13.1.0"
17
17
  },
18
18
  "devDependencies": {
package/src/cli.js CHANGED
@@ -184,9 +184,9 @@ program
184
184
  )
185
185
  .option(
186
186
  '--env <vars>',
187
- 'Environment variables for every command the Client runs for the job (git, docker login, --command): ' +
187
+ 'Environment variables for every command the Client runs for the job (git, --command): ' +
188
188
  'NAME=value[,NAME=value] (repeatable; a value may contain commas); --env NAME alone takes its value from this shell. ' +
189
- 'With DOCKER_REGISTRY, DOCKER_USERNAME and DOCKER_PASSWORD the Client first logs in to that registry. ' +
189
+ 'Any names (except THUB_*, GIT_TERMINAL_PROMPT, GIT_ALLOW_PROTOCOL). ' +
190
190
  'Values reach only the Client running the job; the Coordinator masks them and drops them when the job ends',
191
191
  collectRepeatable,
192
192
  []
@@ -28,12 +28,12 @@ const NPM_STDIO = ['inherit', 2, 2],
28
28
  // for a system-wide install. Never throws — returns whether it worked.
29
29
  function installAgent(target){
30
30
  try {
31
- if (npmInstallGlobal(PACKAGES.agent, target, { stdio: NPM_STDIO }) === 0){
31
+ if (npmInstallGlobal(PACKAGES.agent, target, { stdio: NPM_STDIO, retryDelaysSec: [] }) === 0){
32
32
  return true;
33
33
  }
34
34
  if (process.getuid?.() !== 0 && process.stdin.isTTY){
35
35
  console.error('thub: retrying with sudo');
36
- return spawnSync('sudo', [npmBin(), 'i', '-g', `${PACKAGES.agent}@${target}`], { stdio: NPM_STDIO }).status === 0;
36
+ return spawnSync('sudo', [npmBin(), 'i', '-g', '--prefer-online', `${PACKAGES.agent}@${target}`], { stdio: NPM_STDIO }).status === 0;
37
37
  }
38
38
  }
39
39
  catch (err){