cuonztech-privacy-chaos-gate 0.2.0 → 0.2.2

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/action.yml CHANGED
@@ -10,11 +10,15 @@ inputs:
10
10
  description: "The URL of the staging or localhost web environment to stress-test"
11
11
  required: true
12
12
  api-key:
13
- description: "API key for the auto-remediation LLM (e.g. OpenAI, Anthropic, Gemini)"
13
+ description: "API key for the optional LLM patch generation. Only OpenAI is implemented (llm-provider openai); other providers fall back to the built-in rules. Has no effect without llm-remediation: true. Passed via the CPCG_LLM_API_KEY environment variable."
14
14
  required: false
15
15
  default: ""
16
+ llm-remediation:
17
+ description: "Opt-in: allow the source code to be sent to the LLM provider (OpenAI only) to generate patches (needs api-key). Off by default; only passed on if the installed CLI supports it."
18
+ required: false
19
+ default: "false"
16
20
  llm-provider:
17
- description: "LLM Provider to use for auto-remediation ('openai', 'anthropic', 'gemini')"
21
+ description: "LLM provider for auto-remediation. Only 'openai' is implemented; 'anthropic' and 'gemini' fall back to the built-in rules."
18
22
  required: false
19
23
  default: "openai"
20
24
  llm-model:
@@ -22,13 +26,49 @@ inputs:
22
26
  required: false
23
27
  default: "gpt-4o"
24
28
  auto-fix:
25
- description: "Automatically generate and apply code patches when tracker leaks are detected"
29
+ description: "Generate and apply code patches on the runner when tracker leaks are detected. Off by default: a gate should not silently change files; combine with create-pr to receive the fix as a pull request."
26
30
  required: false
27
- default: "true"
31
+ default: "false"
28
32
  fail-on-leak:
29
33
  description: "Block the build (exit code 1) if unpatched critical leaks remain"
30
34
  required: false
31
35
  default: "true"
36
+ fail-on-uncheckable:
37
+ description: "Block the build (exit code 4) if core scenarios could not be checked conclusively (e.g. consent banner not found). Only passed on if the installed CLI supports it; otherwise a warning is printed."
38
+ required: false
39
+ default: "true"
40
+ strict:
41
+ description: "Hints (purely functional third parties such as Google Fonts) also block the gate. Off by default: they are reported as hints, not as blockers. Only passed on if the installed CLI supports it."
42
+ required: false
43
+ default: "false"
44
+ ignore:
45
+ description: "Findings to ignore: tracker name or host pattern, one per line or comma-separated (e.g. fonts.googleapis.com or *.hotjar.com). Ignored findings are listed as ignored in the report."
46
+ required: false
47
+ default: ""
48
+ accept-selector:
49
+ description: "Own CSS selector of the accept button, one per line (when the built-in CMP detection does not find it)"
50
+ required: false
51
+ default: ""
52
+ reject-selector:
53
+ description: "Own CSS selector of the reject button, one per line"
54
+ required: false
55
+ default: ""
56
+ settings-selector:
57
+ description: "Own CSS selector of the settings button, one per line"
58
+ required: false
59
+ default: ""
60
+ banner-frame:
61
+ description: "Part of the URL of the iframe that contains the consent banner (CMP inside a frame)"
62
+ required: false
63
+ default: ""
64
+ max-subpages:
65
+ description: "Maximum number of linked subpages checked for trackers (default 12, max 40; larger values take longer)"
66
+ required: false
67
+ default: ""
68
+ banner-wait:
69
+ description: "Seconds to wait for a late consent banner (1-60; default as in the CLI)"
70
+ required: false
71
+ default: ""
32
72
  report-output:
33
73
  description: "File path where the JSON LeakReport will be written"
34
74
  required: false
@@ -38,23 +78,31 @@ inputs:
38
78
  required: false
39
79
  default: "."
40
80
  git-commit:
41
- description: "Automatically commit generated privacy fixes into the branch"
81
+ description: "Commit generated privacy fixes into the checked-out branch (requires auto-fix and a valid license; skipped without one)"
82
+ required: false
83
+ default: "false"
84
+ create-pr:
85
+ description: "Create a fix branch and open a GitHub Pull Request with the generated fix (requires auto-fix, github-token and a valid license; takes precedence over git-commit)"
42
86
  required: false
43
87
  default: "false"
88
+ github-token:
89
+ description: "GitHub token for create-pr (contents: write and pull-requests: write). Passed via the GITHUB_TOKEN environment variable, never on the command line."
90
+ required: false
91
+ default: ""
44
92
  license:
45
- description: "CuonzTech CPCG Lizenzcode (CPCG-…) — aus Secrets, nach Online-Kauf"
93
+ description: "CuonzTech CPCG license (CPCG-… or customer key CPCG-K-…) — from secrets, after online purchase. Not needed for scan and console gate; required for customer report/PDF, git-commit and create-pr. Passed via the CPCG_LICENSE environment variable."
46
94
  required: false
47
95
  default: ""
48
96
  report-pdf:
49
- description: "Deluxe-PDF (Deckblatt + Evidence) nach dem Scan erzeugen"
97
+ description: "Create the deluxe PDF (cover page + evidence) after the scan. Requires a valid license; skipped without one."
50
98
  required: false
51
99
  default: "false"
52
100
  client-name:
53
- description: "Kundenname für das PDF-Deckblatt"
101
+ description: "Client name for the customer report and the PDF cover page. Requires a valid license."
54
102
  required: false
55
103
  default: ""
56
104
  jurisdiction:
57
- description: "Rechtsraum für Bewertung: CH | EU | UK | US-CA | BR | ROW"
105
+ description: "Jurisdiction highlighted in the console and report: CH | EU | UK | US-CA | BR | ROW"
58
106
  required: false
59
107
  default: "CH"
60
108
 
@@ -71,39 +119,152 @@ outputs:
71
119
  report-path:
72
120
  description: "Absolute or relative path to the generated JSON report"
73
121
  value: ${{ steps.cpcg-run.outputs.report_path }}
122
+ gate_state:
123
+ description: "Gate result as written by the CLI (for example blocked, fix-proposed, inconclusive, passed). Empty if the installed CLI predates this output."
124
+ value: ${{ steps.cpcg-run.outputs.gate_state }}
125
+ incomplete:
126
+ description: "'true' if core scenarios could not be checked conclusively"
127
+ value: ${{ steps.cpcg-run.outputs.incomplete }}
128
+ uncheckable_count:
129
+ description: "Number of scenarios that could not be checked"
130
+ value: ${{ steps.cpcg-run.outputs.uncheckable_count }}
131
+ leak_requests:
132
+ description: "Number of tracker requests observed before consent"
133
+ value: ${{ steps.cpcg-run.outputs.leak_requests }}
134
+ exit_code:
135
+ description: "Exit code of the CLI (0 ok, 1 leaks, 2 license invalid or revoked, 3 error, 4 incomplete)"
136
+ value: ${{ steps.cpcg-run.outputs.exit_code }}
74
137
 
75
138
  runs:
76
139
  using: "composite"
77
140
  steps:
78
141
  - name: Setup Node.js
79
- uses: actions/setup-node@v4
142
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
80
143
  with:
81
144
  node-version: "20"
82
145
 
146
+ # Installationsschritt: bewusst ohne Secrets (Lizenz, Token, API-Key) in der Umgebung. Nur hier läuft npm.
147
+ - name: Install Privacy Chaos Gate
148
+ id: cpcg-install
149
+ shell: bash
150
+ env:
151
+ ACTION_PATH: ${{ github.action_path }}
152
+ CPCG_PINNED_VERSION: "0.2.2" # = package.json version; bei jedem Release mit anheben (tests/action-pin.test.ts prüft das)
153
+ run: |
154
+ set -euo pipefail
155
+
156
+ CLI_PATH="$ACTION_PATH/dist/cli.js"
157
+ if [ -f "$CLI_PATH" ]; then
158
+ # Eigener Build im Action-Pfad (Repo-CI): Abhängigkeiten und Browser bringt der Workflow mit.
159
+ echo "cli=$CLI_PATH" >> "$GITHUB_OUTPUT"
160
+ exit 0
161
+ fi
162
+
163
+ # Veröffentlichtes Paket in der gepinnten Version. Lifecycle-Skripte der Abhängigkeiten laufen nicht
164
+ # (--ignore-scripts); der Playwright-Browser wird unten ausdrücklich installiert.
165
+ TOOL_DIR="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/cpcg-XXXXXX")"
166
+ npm install --prefix "$TOOL_DIR" --ignore-scripts --no-audit --no-fund --loglevel=error "cuonztech-privacy-chaos-gate@${CPCG_PINNED_VERSION}"
167
+ PW_CLI="$TOOL_DIR/node_modules/playwright/cli.js"
168
+ if [ -f "$PW_CLI" ]; then
169
+ node "$PW_CLI" install --with-deps chromium
170
+ else
171
+ npx --yes playwright install --with-deps chromium
172
+ fi
173
+ echo "cli=$TOOL_DIR/node_modules/cuonztech-privacy-chaos-gate/dist/cli.js" >> "$GITHUB_OUTPUT"
174
+
83
175
  - name: Run Privacy Chaos Gate
84
176
  id: cpcg-run
85
177
  shell: bash
178
+ # Alle Inputs gelangen nur über env in das Skript (keine ${{ }}-Interpolation im run-Block:
179
+ # sonst könnten Input-Werte als Shell-Code ausgeführt werden). Die Lizenz steht nie in der Kommandozeile.
86
180
  env:
181
+ CPCG_CLI: ${{ steps.cpcg-install.outputs.cli }}
87
182
  CPCG_LLM_API_KEY: ${{ inputs.api-key }}
88
183
  CPCG_LLM_PROVIDER: ${{ inputs.llm-provider }}
89
184
  CPCG_LLM_MODEL: ${{ inputs.llm-model }}
90
185
  CPCG_LICENSE: ${{ inputs.license }}
186
+ GITHUB_TOKEN: ${{ inputs.github-token }}
187
+ IN_STAGING_URL: ${{ inputs.staging-url }}
188
+ IN_LLM_REMEDIATION: ${{ inputs.llm-remediation }}
189
+ IN_AUTO_FIX: ${{ inputs.auto-fix }}
190
+ IN_FAIL_ON_LEAK: ${{ inputs.fail-on-leak }}
191
+ IN_FAIL_ON_UNCHECKABLE: ${{ inputs.fail-on-uncheckable }}
192
+ IN_STRICT: ${{ inputs.strict }}
193
+ IN_IGNORE: ${{ inputs.ignore }}
194
+ IN_ACCEPT_SELECTOR: ${{ inputs.accept-selector }}
195
+ IN_REJECT_SELECTOR: ${{ inputs.reject-selector }}
196
+ IN_SETTINGS_SELECTOR: ${{ inputs.settings-selector }}
197
+ IN_BANNER_FRAME: ${{ inputs.banner-frame }}
198
+ IN_MAX_SUBPAGES: ${{ inputs.max-subpages }}
199
+ IN_BANNER_WAIT: ${{ inputs.banner-wait }}
200
+ IN_REPORT_OUTPUT: ${{ inputs.report-output }}
201
+ IN_SOURCE_DIR: ${{ inputs.target-source-dir }}
202
+ IN_GIT_COMMIT: ${{ inputs.git-commit }}
203
+ IN_CREATE_PR: ${{ inputs.create-pr }}
204
+ IN_REPORT_PDF: ${{ inputs.report-pdf }}
205
+ IN_CLIENT: ${{ inputs.client-name }}
206
+ IN_JURISDICTION: ${{ inputs.jurisdiction }}
91
207
  run: |
92
- CLI_PATH="${{ github.action_path }}/dist/cli.js"
93
- if [ -f "$CLI_PATH" ]; then
94
- RUNNER="node $CLI_PATH"
95
- else
96
- RUNNER="npx @cuonztech/privacy-chaos-gate"
208
+ set -euo pipefail
209
+
210
+ RUNNER=(node "$CPCG_CLI")
211
+
212
+ # Optionen immer als --name=wert: ein Wert, der mit "-" beginnt, wird so nie als eigene Option gelesen.
213
+ ARGS=(
214
+ "--url=$IN_STAGING_URL"
215
+ "--auto-fix=$IN_AUTO_FIX"
216
+ "--fail-on-leak=$IN_FAIL_ON_LEAK"
217
+ "--report-output=$IN_REPORT_OUTPUT"
218
+ "--source-dir=$IN_SOURCE_DIR"
219
+ "--git-commit=$IN_GIT_COMMIT"
220
+ "--create-pr=$IN_CREATE_PR"
221
+ "--report-pdf=$IN_REPORT_PDF"
222
+ "--jurisdiction=$IN_JURISDICTION"
223
+ )
224
+ if [ -n "$IN_CLIENT" ]; then
225
+ ARGS+=("--client=$IN_CLIENT")
97
226
  fi
98
227
 
99
- $RUNNER \
100
- --url "${{ inputs.staging-url }}" \
101
- --auto-fix "${{ inputs.auto-fix }}" \
102
- --fail-on-leak "${{ inputs.fail-on-leak }}" \
103
- --report-output "${{ inputs.report-output }}" \
104
- --source-dir "${{ inputs.target-source-dir }}" \
105
- --git-commit "${{ inputs.git-commit }}" \
106
- --license "${{ inputs.license }}" \
107
- --report-pdf "${{ inputs.report-pdf }}" \
108
- --client "${{ inputs.client-name }}" \
109
- --jurisdiction "${{ inputs.jurisdiction }}"
228
+ # Neuere Optionen nur weitergeben, wenn die installierte CLI sie kennt (ältere Versionen würden sonst mit
229
+ # "unknown option" abbrechen). Kennt sie eine gewünschte Option nicht, wird das gemeldet, nicht still übergangen.
230
+ HELP="$("${RUNNER[@]}" --help 2>&1 || true)"
231
+ supports() { printf '%s\n' "$HELP" | grep -q -- "$1"; }
232
+ warn_unsupported() {
233
+ echo "::warning title=CPCG::Die installierte CLI kennt --$1 nicht; der Input wird ignoriert. Paket- und Action-Version angleichen."
234
+ }
235
+ # Boolesche Option: übergeben, wenn bekannt; unbekannt und angefordert ("true") → Warnung.
236
+ opt_bool() {
237
+ if supports "--$1"; then
238
+ ARGS+=("--$1=$2")
239
+ elif [ "$2" = "true" ]; then
240
+ warn_unsupported "$1"
241
+ fi
242
+ return 0
243
+ }
244
+ # Wert-Option (mehrzeilig erlaubt: je nichtleere Zeile eine Option): nur wenn gesetzt.
245
+ opt_lines() {
246
+ local flag="$1" value="$2" line
247
+ [ -n "${value//[[:space:]]/}" ] || return 0
248
+ if ! supports "--$flag"; then
249
+ warn_unsupported "$flag"
250
+ return 0
251
+ fi
252
+ while IFS= read -r line; do
253
+ line="${line#"${line%%[![:space:]]*}"}"
254
+ line="${line%"${line##*[![:space:]]}"}"
255
+ if [ -n "$line" ]; then ARGS+=("--$flag=$line"); fi
256
+ done <<< "$value"
257
+ return 0
258
+ }
259
+ opt_bool fail-on-uncheckable "$IN_FAIL_ON_UNCHECKABLE"
260
+ opt_bool llm-remediation "$IN_LLM_REMEDIATION"
261
+ opt_bool strict "$IN_STRICT"
262
+ opt_lines ignore "$IN_IGNORE"
263
+ opt_lines accept-selector "$IN_ACCEPT_SELECTOR"
264
+ opt_lines reject-selector "$IN_REJECT_SELECTOR"
265
+ opt_lines settings-selector "$IN_SETTINGS_SELECTOR"
266
+ opt_lines banner-frame "$IN_BANNER_FRAME"
267
+ opt_lines max-subpages "$IN_MAX_SUBPAGES"
268
+ opt_lines banner-wait "$IN_BANNER_WAIT"
269
+
270
+ "${RUNNER[@]}" "${ARGS[@]}"