Skip to content

Commit 2d6217b

Browse files
committed
Merge branch 'master' into fix/trace-diagnostics-to-stderr
2 parents d6257f8 + 6cbca61 commit 2d6217b

6 files changed

Lines changed: 73 additions & 15 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,10 +652,21 @@ jobs:
652652
runs-on: ubuntu-latest
653653
steps:
654654
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
655+
# setup-alpine downloads apk.static with a single 10s-timeout curl, and the gitlab mirror
656+
# is unreliable from CI runners. Pre-fetch it with retries into the path setup-alpine
657+
# caches ($RUNNER_TEMP/apk); the action then skips its own flaky download.
658+
- name: Pre-fetch x86_64 apk.static (work around flaky gitlab mirror)
659+
run: |
660+
mkdir -p "$RUNNER_TEMP"
661+
curl -4 -fsSL --retry 5 --retry-all-errors --retry-delay 5 --connect-timeout 30 --max-time 180 \
662+
-o "$RUNNER_TEMP/apk" \
663+
https://gitlab.alpinelinux.org/api/v4/projects/5/packages/generic/v2.14.10/x86_64/apk.static
664+
echo "34bb1a96f0258982377a289392d4ea9f3f4b767a4bb5806b1b87179b79ad8a1c $RUNNER_TEMP/apk" | sha256sum -c
655665
- name: Setup Alpine
656666
uses: jirutka/setup-alpine@ae3b3ddba35054804fc4a3507b519fa7e8152050 # v1.4.1
657667
with:
658668
shell-name: alpine.sh
669+
apk-tools-url: https://gitlab.alpinelinux.org/api/v4/projects/5/packages/generic/v2.14.10/x86_64/apk.static#!sha256!34bb1a96f0258982377a289392d4ea9f3f4b767a4bb5806b1b87179b79ad8a1c
659670
- name: Install project dependencies (root)
660671
run: |
661672
apk add npm git
@@ -695,7 +706,7 @@ jobs:
695706
steps:
696707
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
697708
# setup-alpine downloads apk.static with a single 10s-timeout curl, and the gitlab mirror
698-
# is unreliable from arm64 runners. Pre-fetch it with retries into the path setup-alpine
709+
# is unreliable from CI runners. Pre-fetch it with retries into the path setup-alpine
699710
# caches ($RUNNER_TEMP/apk); the action then skips its own flaky download.
700711
- name: Pre-fetch aarch64 apk.static (work around flaky gitlab mirror)
701712
run: |

packages/base/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@
145145
"terminal-link": "^2.1.1",
146146
"tiny-async-pool": "^2.1.0",
147147
"typanion": "^3.14.0",
148-
"undici": "^7.24.6",
148+
"undici": "^7.28.0",
149149
"upath": "^2.0.1"
150150
},
151151
"devDependencies": {

packages/base/src/commands/trace/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Trace a command with a custom span and report it to Datadog.
55
## Usage
66

77
```bash
8-
datadog-ci trace [--name <name>] [--tags] [--measures] [--no-fail] [--dry-run] -- <command>
8+
datadog-ci trace [--name <name>] [--tags] [--measures] [--no-fail] [--no-capture] [--dry-run] -- <command>
99
```
1010

1111
For example:
@@ -21,6 +21,7 @@ datadog-ci trace --name "Say Hello" -- echo "Hello World"
2121
- `--measures` is an array of key-value pairs with the format `key:value`. These measures are added to the custom span.
2222
The `value` must be a number.
2323
- `--no-fail` (default: `false`) will prevent the trace command from failing even when not run in a supported CI Provider. In this case, the command will be launched and nothing will be reported to Datadog.
24+
- `--no-capture` (default: `false`) reports only the executable name instead of the full command line, so potentially sensitive arguments (tokens, secrets, etc.) are not sent to Datadog. The command is still launched with all of its arguments; only the reported span is trimmed. When `--name` is not provided, the span name also defaults to the executable name.
2425
- `--dry-run` (default: `false`) runs the command without sending the custom span. All other checks are performed.
2526

2627
#### Environment variables

packages/base/src/commands/trace/__tests__/trace.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,43 @@ describe('trace', () => {
7070
})
7171
})
7272

73+
describe('no-capture', () => {
74+
// Runs `trace` (in --dry-run) with a full command line including arguments, and returns the
75+
// custom span payload that would have been reported (emitted to stdout by --dry-run).
76+
const runWithCommand = async (extraArgs: string[], command: string[]) => {
77+
const cli = new Cli()
78+
cli.register(TraceCommand)
79+
80+
process.env = {...getEnvVarPlaceholders(), CIRCLECI: 'true'}
81+
const context = createMockContext({env: process.env})
82+
context.stderr = new PassThrough()
83+
const code = await cli.run(['trace', '--dry-run', ...extraArgs, '--', ...command], context)
84+
85+
const stdout = context.stdout.toString()
86+
const match = stdout.match(/Reporting custom span: (\{.*\})/)
87+
const payload = match ? JSON.parse(match[1]) : undefined
88+
89+
return {code, payload}
90+
}
91+
92+
test('captures the full command line by default', async () => {
93+
const {payload} = await runWithCommand([], ['echo', '--token', 'secret'])
94+
expect(payload.command).toBe('echo --token secret')
95+
expect(payload.name).toBe('echo --token secret')
96+
})
97+
98+
test('reports only the executable name with --no-capture', async () => {
99+
const {payload} = await runWithCommand(['--no-capture'], ['echo', '--token', 'secret'])
100+
expect(payload.command).toBe('echo')
101+
expect(payload.name).toBe('echo')
102+
})
103+
104+
test('still honors an explicit --name with --no-capture', async () => {
105+
const {payload} = await runWithCommand(['--no-capture', '--name', 'Deploy'], ['echo', '--token', 'secret'])
106+
expect(payload.command).toBe('echo')
107+
expect(payload.name).toBe('Deploy')
108+
})
109+
})
110+
73111
makeCIProviderTests(runCLI, [])
74112
})

packages/base/src/commands/trace/trace.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,17 @@ export class TraceCommand extends CustomSpanCommand {
3131
'Trace a command and report to the datadoghq.eu site',
3232
'DD_SITE=datadoghq.eu datadog-ci trace -- echo "Hello World"',
3333
],
34+
[
35+
'Trace a command without capturing its arguments (e.g. when they contain secrets)',
36+
'datadog-ci trace --no-capture -- ./deploy.sh --token "$SECRET"',
37+
],
3438
],
3539
})
3640

3741
private command = Option.Rest({required: 1})
3842
private name = Option.String('--name')
3943
private noFail = Option.Boolean('--no-fail')
44+
private noCapture = Option.Boolean('--no-capture')
4045

4146
public async execute() {
4247
this.tryEnableFips()
@@ -77,7 +82,10 @@ export class TraceCommand extends CustomSpanCommand {
7782
const stderr: string = await stderrCatcher
7883
const endTime = new Date()
7984
const exitCode: number = status ?? this.signalToNumber(signal) ?? BAD_COMMAND_EXIT_CODE
80-
const commandStr = this.command.join(' ')
85+
// With `--no-capture`, only report the executable name so that potentially sensitive
86+
// arguments (tokens, secrets, etc.) are not sent to Datadog. The child still runs with
87+
// the full argument list above; only what we report is trimmed.
88+
const commandStr = this.noCapture ? command : this.command.join(' ')
8189

8290
const res = await this.executeReportCustomSpan(id, startTime, endTime, {
8391
command: commandStr,

yarn.lock

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,7 @@ __metadata:
14381438
terminal-link: "npm:^2.1.1"
14391439
tiny-async-pool: "npm:^2.1.0"
14401440
typanion: "npm:^3.14.0"
1441-
undici: "npm:^7.24.6"
1441+
undici: "npm:^7.28.0"
14421442
upath: "npm:^2.0.1"
14431443
peerDependencies:
14441444
"@datadog/datadog-ci-plugin-aas": "workspace:*"
@@ -5429,9 +5429,9 @@ __metadata:
54295429
linkType: hard
54305430

54315431
"basic-ftp@npm:^5.0.2":
5432-
version: 5.2.0
5433-
resolution: "basic-ftp@npm:5.2.0"
5434-
checksum: 10/f5a15d789aa98859af4da9e976154b2aeae19052e1762dc68d259d2bce631dafa40c667aa06d7346cd630aa6f9cc9a26f515b468e0bd24243fbae2149c7d01ad
5432+
version: 5.3.1
5433+
resolution: "basic-ftp@npm:5.3.1"
5434+
checksum: 10/9232ee155114efafadf5adee86a6750208653a9071e53e9803dceac61a66b3ba3974771ff2490ff28f1a118fdfb806ffcc488f64609e61a9cedb52480b312843
54355435
languageName: node
54365436
linkType: hard
54375437

@@ -7345,9 +7345,9 @@ __metadata:
73457345
linkType: hard
73467346

73477347
"flatted@npm:^3.2.9":
7348-
version: 3.3.1
7349-
resolution: "flatted@npm:3.3.1"
7350-
checksum: 10/7b8376061d5be6e0d3658bbab8bde587647f68797cf6bfeae9dea0e5137d9f27547ab92aaff3512dd9d1299086a6d61be98e9d48a56d17531b634f77faadbc49
7348+
version: 3.4.2
7349+
resolution: "flatted@npm:3.4.2"
7350+
checksum: 10/a9e78fe5c2c1fcd98209a015ccee3a6caa953e01729778e83c1fe92e68601a63e1e69cd4e573010ca99eaf585a581b80ccf1018b99283e6cbc2117bcba1e030f
73517351
languageName: node
73527352
linkType: hard
73537353

@@ -11817,10 +11817,10 @@ __metadata:
1181711817
languageName: node
1181811818
linkType: hard
1181911819

11820-
"undici@npm:^7.24.6":
11821-
version: 7.25.0
11822-
resolution: "undici@npm:7.25.0"
11823-
checksum: 10/038d3568c72bb976e3cc389284f7f1cc64cd70d578300e4676a449fbcb624a35fe99ac127b5f3729f18b8246d6c090444ab61b1b67736bb88f52a3e913d76bf8
11820+
"undici@npm:^7.28.0":
11821+
version: 7.28.0
11822+
resolution: "undici@npm:7.28.0"
11823+
checksum: 10/154423b280d623278a61decb437f8a7e581fb18b8c95556ef956b32a58cd668eadbb812d28e20678cb2dc545a566f35a3afc0962307ca801da30f4741117986d
1182411824
languageName: node
1182511825
linkType: hard
1182611826

0 commit comments

Comments
 (0)