master
sh 87 lines 2.43 KB
Raw
1 #!/usr/bin/env bash
2 # redact-events.sh -- opt-in redaction of identifying fields.
3 #
4 # Replaces UUID-shaped values in known identifying fields with
5 # stable placeholders like <redacted-A>, <redacted-B>, ... so
6 # patterns are still identifiable (same machine_guid -> same
7 # placeholder within the dump) but the raw value is gone.
8 #
9 # Use this only when sharing a dump externally. Default
10 # workflow keeps raw events under .local/audits/...
11 # (gitignored).
12
13 set -euo pipefail
14
15 usage() {
16 cat <<'EOF'
17 redact-events.sh [--input PATH] [--output PATH]
18
19 Redacts identifying fields in a Function-envelope JSON dump or
20 a flat array of objects.
21
22 Identifying fields redacted:
23 AE_AGENT_ID, AE_HOST_ID, AE_AGENT_NODE_ID, AE_AGENT_CLAIM_ID,
24 AE_HOST_BOOT_ID, AE_AGENT_EPHEMERAL_ID, AE_HW_SYS_UUID,
25 _MACHINE_ID, _BOOT_ID
26
27 Stable mapping: same value -> same placeholder within the dump.
28
29 Defaults:
30 --input stdin
31 --output stdout
32 EOF
33 }
34
35 INPUT=
36 OUTPUT=
37 while [ $# -gt 0 ]; do
38 case "$1" in
39 --input) INPUT="$2"; shift 2 ;;
40 --output) OUTPUT="$2"; shift 2 ;;
41 -h|--help) usage; exit 0 ;;
42 *) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
43 esac
44 done
45
46 if [ -n "$INPUT" ]; then exec < "$INPUT"; fi
47 if [ -n "$OUTPUT" ]; then exec > "$OUTPUT"; fi
48
49 jq -c '
50 def redact_fields:
51 ["AE_AGENT_ID","AE_HOST_ID","AE_AGENT_NODE_ID","AE_AGENT_CLAIM_ID",
52 "AE_HOST_BOOT_ID","AE_AGENT_EPHEMERAL_ID","AE_HW_SYS_UUID",
53 "_MACHINE_ID","_BOOT_ID"];
54
55 def alphabet:
56 ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
57 "Q","R","S","T","U","V","W","X","Y","Z"];
58
59 . as $root
60 | reduce (redact_fields[]) as $f (
61 {state: {map: {}, idx: 0}, root: $root};
62 . as {state: $st, root: $r}
63 | ($r | .. | objects | select(has($f)) | .[$f] | tostring) as $vals
64 | reduce $vals as $v (
65 .;
66 if (.state.map | has($v)) then
67 .
68 else
69 .state.map[$v] = ("<redacted-" + (alphabet[(.state.idx % 26)]) + (if .state.idx >= 26 then ((.state.idx / 26 | floor) | tostring) else "" end) + ">")
70 | .state.idx += 1
71 end
72 )
73 )
74 | .root as $r
75 | .state.map as $m
76 | ($r | walk(
77 if type == "object" then
78 with_entries(
79 if (.key | IN("AE_AGENT_ID","AE_HOST_ID","AE_AGENT_NODE_ID","AE_AGENT_CLAIM_ID","AE_HOST_BOOT_ID","AE_AGENT_EPHEMERAL_ID","AE_HW_SYS_UUID","_MACHINE_ID","_BOOT_ID"))
80 then .value = ($m[(.value | tostring)] // .value)
81 else .
82 end
83 )
84 else .
85 end
86 ))
87 '