Repository navigation
235 lines (214 loc) · 9.28 KB
/
Copy pathcode-scan.yml
File metadata and controls
235 lines (214 loc) · 9.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
name: Code Scan
# Static analysis of contributed code, using Microsoft and GitHub tooling
# rather than bespoke rules:
#
# CodeQL — dataflow analysis of contributed catalog Python.
# DevSkim — Microsoft's security linter (microsoft/DevSkim).
# ApplicationInspector— Microsoft's characterization scanner. Answers "what
# does this code actually DO" (network, shell, crypto,
# file I/O), which is the question a reviewer of an
# untrusted scientific tool most needs answered.
#
# Every analyzer in this workflow is scoped to contributed catalog code under
# agents/ and starter-kits/.
#
# Rollout posture: reporting, not gating. Pointing three new analyzers at 46
# pre-existing agents would produce a flood of findings that blocks unrelated
# contributions. Findings are retained as downloadable artifacts; promote to
# blocking once the backlog is triaged, the same way the rule engine's ratchet
# works.
on:
pull_request:
paths:
- "agents/**"
- "starter-kits/**"
push:
branches: [main]
paths:
- "agents/**"
- "starter-kits/**"
schedule:
# 06:00 UTC Monday — a full-catalog sweep that *raises* pre-existing
# breakage (e.g. a contributed file CodeQL cannot even parse). On a PR the
# same analysis is non-gating (see continue-on-error below): it reports on
# what the PR changed without blocking on unrelated legacy debt.
- cron: "0 6 * * 1"
workflow_dispatch:
permissions:
contents: read
security-events: write
concurrency:
group: code-scan-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
# ── CodeQL over contributed catalog code ─────────────────────────────────
codeql:
name: CodeQL (${{ matrix.scope }})
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- language: python
scope: catalog-python
config: ./.github/codeql/codeql-config.yml
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize CodeQL
# Reporting posture on PRs: a pre-existing file the extractor cannot
# parse must not fail an unrelated contributor's PR. Scheduled and
# push runs stay gating so the breakage is raised for triage.
continue-on-error: ${{ github.event_name == 'pull_request' }}
uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
with:
languages: ${{ matrix.language }}
config-file: ${{ matrix.config }}
- name: Analyze
continue-on-error: ${{ github.event_name == 'pull_request' }}
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
with:
category: "/language:${{ matrix.language }}/scope:${{ matrix.scope }}"
output: codeql-results
# This repository has CodeQL default setup enabled, which rejects
# SARIF uploads from advanced configurations. Keep the scoped scan
# and publish its SARIF through the artifact step below instead.
upload: false
- name: Upload CodeQL SARIF artifact
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: codeql-${{ matrix.scope }}-sarif
path: codeql-results
if-no-files-found: warn
# ── DevSkim security lint ─────────────────────────────────────────────────
devskim:
name: DevSkim
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# The action scans a single directory, so the two guarded trees are
# scanned separately and their SARIF kept apart by category below.
- name: Scan agents/
uses: microsoft/DevSkim-Action@4b5047945a44163b94642a1cecc0d93a3f428cc6 # v1
with:
directory-to-scan: agents
output-filename: devskim-agents.sarif
ignore-globs: "**/.git/**,agents/tmp/**"
- name: Scan starter-kits/
uses: microsoft/DevSkim-Action@4b5047945a44163b94642a1cecc0d93a3f428cc6 # v1
with:
directory-to-scan: starter-kits
output-filename: devskim-starter-kits.sarif
ignore-globs: "**/.git/**,starter-kits/tmp/**"
# A fork PR runs with a read-only token, so the Security tab upload is
# not available. Skip it there rather than failing the job; the artifact
# below carries the same findings for the reviewer either way.
- name: Upload agents SARIF
if: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request' }}
continue-on-error: true
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
with:
sarif_file: devskim-agents.sarif
category: devskim-agents
- name: Upload starter-kits SARIF
if: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request' }}
continue-on-error: true
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4
with:
sarif_file: devskim-starter-kits.sarif
category: devskim-starter-kits
- name: Summarize findings
if: always()
run: |
set -uo pipefail
summarize() {
local file="$1"; local label="$2"
[ -f "$file" ] || { echo "- **$label**: no output produced."; return; }
local count
count=$(python -c "
import json, sys
try:
d = json.load(open('$file'))
print(sum(len(r.get('results', [])) for r in d.get('runs', [])))
except Exception:
print('?')
")
echo "- **$label**: $count finding(s)."
}
{
echo "## DevSkim"
echo
summarize devskim-agents.sarif "agents/"
summarize devskim-starter-kits.sarif "starter-kits/"
echo
echo "Findings are reported, not enforced. Download the \`devskim-sarif\` artifact for detail."
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload SARIF artifacts
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: devskim-sarif
path: devskim-*.sarif
if-no-files-found: warn
# ── What does this code actually do? ──────────────────────────────────────
capabilities:
name: Capability report
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: "8.0"
- name: Restore Application Inspector
run: dotnet tool restore
# Application Inspector reports features rather than defects: network
# calls, shell execution, cryptography, file and cloud APIs. For an
# untrusted scientific tool that is the review question — a retrosynthesis
# container has no business opening sockets.
#
# One invocation per tree, matching the DevSkim steps above, rather than
# relying on multi-source flag behaviour.
- name: Characterize contributed code
run: |
set -uo pipefail
scan() {
local dir="$1"; local out="$2"
[ -d "$dir" ] || { echo "_No $dir directory._" > "$out"; return; }
dotnet tool run appinspector analyze \
-s "$dir" \
-f markdown \
-o "$out" \
-g "**/.git/**,**/tmp/**" \
|| echo "_Application Inspector exited non-zero for $dir._" >> "$out"
}
scan agents capabilities-agents.md
scan starter-kits capabilities-starter-kits.md
{
echo "## Capability report"
echo
echo "What the contributed code does, per Microsoft Application Inspector."
echo "Review anything unexpected for the agent's stated purpose — network"
echo "calls, shell execution, or cryptography in a tool that should not need them."
echo
echo "<details><summary>agents/</summary>"
echo
head -c 40000 capabilities-agents.md 2>/dev/null || echo "_No report._"
echo
echo "</details>"
echo
echo "<details><summary>starter-kits/</summary>"
echo
head -c 10000 capabilities-starter-kits.md 2>/dev/null || echo "_No report._"
echo
echo "</details>"
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload capability report
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: capability-report
path: capabilities-*.md
if-no-files-found: warn