Skip to content

Commit 779a043

Browse files
Copilotpelikhan
andauthored
Fix security observability cache warm-start and stale handling
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
1 parent c1ea3f7 commit 779a043

2 files changed

Lines changed: 73 additions & 8 deletions

File tree

.github/workflows/daily-security-observability.lock.yml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/daily-security-observability.md

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,82 @@ steps:
3737
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3838
run: |
3939
mkdir -p /tmp/gh-aw/agent/integrity
40+
mkdir -p /tmp/gh-aw/cache-memory/security-observability
41+
42+
CACHE_FILE=/tmp/gh-aw/cache-memory/security-observability/filtered-logs.snapshot.json
43+
RUN_FILE=/tmp/gh-aw/agent/integrity/filtered-logs.json
44+
FRESH_LOGS=/tmp/gh-aw/agent/integrity/filtered-logs.fresh.json
45+
EMPTY_DATA='{"runs":[],"summary":{"total_runs":0}}'
46+
NOW_EPOCH=$(date +%s)
47+
MAX_CACHE_AGE_SECONDS=$((7 * 24 * 60 * 60))
48+
49+
# Warm start from cached 7-day snapshot when available and fresh.
50+
if [ -f "$CACHE_FILE" ] && jq -e '.runs and .updated_at' "$CACHE_FILE" > /dev/null 2>&1; then
51+
cache_updated_at=$(jq -r '.updated_at' "$CACHE_FILE")
52+
cache_updated_epoch=$(
53+
date -d "$cache_updated_at" +%s 2>/dev/null \
54+
|| date -j -f "%Y-%m-%dT%H:%M:%SZ" "$cache_updated_at" +%s 2>/dev/null \
55+
|| echo 0
56+
)
57+
cache_age_seconds=$((NOW_EPOCH - cache_updated_epoch))
58+
if [ "$cache_updated_epoch" -gt 0 ] && [ "$cache_age_seconds" -le "$MAX_CACHE_AGE_SECONDS" ]; then
59+
jq '{runs: (.runs // []), summary: (.summary // {"total_runs": 0})}' "$CACHE_FILE" > "$RUN_FILE"
60+
echo "✅ Warm cache restored (${cache_age_seconds}s old)"
61+
else
62+
echo "⚠️ Cache snapshot is stale (${cache_age_seconds}s old); starting fresh"
63+
fi
64+
fi
65+
4066
# Download logs filtered to only runs with DIFC integrity-filtered events.
4167
# --artifacts mcp: only download the MCP gateway log artifact (sufficient for DIFC checking).
4268
# --timeout 8: cap execution at 8 minutes to prevent runaway downloads.
4369
gh aw logs --filtered-integrity --start-date -7d --json -c 200 \
4470
--artifacts mcp --timeout 8 \
45-
> /tmp/gh-aw/agent/integrity/filtered-logs.json || true
71+
> "$FRESH_LOGS" || true
4672
4773
# Validate JSON output and fall back to an empty dataset on failure
48-
if ! jq -e '.runs' /tmp/gh-aw/agent/integrity/filtered-logs.json > /dev/null 2>&1; then
74+
if ! jq -e '.runs' "$FRESH_LOGS" > /dev/null 2>&1; then
4975
echo "⚠️ No valid logs produced; continuing with empty dataset"
50-
echo '{"runs":[],"summary":{"total_runs":0}}' > /tmp/gh-aw/agent/integrity/filtered-logs.json
76+
echo "$EMPTY_DATA" > "$FRESH_LOGS"
5177
fi
5278
53-
count=$(jq '.runs | length' /tmp/gh-aw/agent/integrity/filtered-logs.json 2>/dev/null || echo 0)
79+
# Merge warm-start and fresh runs; fresh entries override warm-cache entries with the same run_id.
80+
if [ -f "$RUN_FILE" ] && jq -e '.runs' "$RUN_FILE" > /dev/null 2>&1; then
81+
jq -s '
82+
{
83+
runs: (
84+
((.[0].runs // []) + (.[1].runs // []))
85+
| sort_by(.run_id)
86+
| group_by(.run_id)
87+
| map(.[-1])
88+
),
89+
summary: {
90+
total_runs: (
91+
((.[0].runs // []) + (.[1].runs // []) | sort_by(.run_id) | group_by(.run_id) | length)
92+
)
93+
}
94+
}
95+
' "$RUN_FILE" "$FRESH_LOGS" > "$RUN_FILE.merged"
96+
mv "$RUN_FILE.merged" "$RUN_FILE"
97+
else
98+
mv "$FRESH_LOGS" "$RUN_FILE"
99+
fi
100+
101+
count=$(jq '.runs | length' "$RUN_FILE" 2>/dev/null || echo 0)
54102
echo "✅ Downloaded $count runs with integrity-filtered events"
55103
104+
# Persist updated 7-day snapshot back to cache-memory every run.
105+
jq -n \
106+
--arg updated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
107+
--slurpfile payload "$RUN_FILE" \
108+
'{
109+
updated_at: $updated_at,
110+
runs: ($payload[0].runs // []),
111+
summary: {
112+
total_runs: (($payload[0].runs // []) | length)
113+
}
114+
}' > "$CACHE_FILE"
115+
56116
tools:
57117
bash:
58118
- "*"
@@ -174,9 +234,14 @@ Upload both charts using `upload_asset` and record the returned URLs.
174234

175235
## Phase 3: Collect DIFC Integrity-Filtered Events
176236

177-
### Step 3.1: Check for DIFC Data
237+
### Step 3.1: Warm Start Validation + DIFC Data Check
238+
239+
The startup step restores a cached snapshot from `/tmp/gh-aw/cache-memory/security-observability/filtered-logs.snapshot.json` before collecting fresh runs.
178240

179-
Read `/tmp/gh-aw/agent/integrity/filtered-logs.json`. If the `runs` array is empty or missing (no runs found in the last 7 days), note "No DIFC integrity-filtered events found in the last 7 days." and proceed directly to Phase 5 (combined report).
241+
1. Verify the restored snapshot age using `updated_at` from the cache file:
242+
- If age is `<= 7 days`, treat it as a valid warm start.
243+
- If age is `> 7 days` or missing, treat it as stale and rely on fresh logs.
244+
2. Read `/tmp/gh-aw/agent/integrity/filtered-logs.json`. If the `runs` array is empty or missing (no runs found in the last 7 days), note "No DIFC integrity-filtered events found in the last 7 days." and proceed directly to Phase 5 (combined report).
180245

181246
### Step 3.2: Fetch Detailed DIFC Gateway Data
182247

0 commit comments

Comments
 (0)