Skip to content

Commit 55d8f45

Browse files
author
Yuma Ichikawa
committed
chore(security): add gitleaks + nbstripout hooks and strip notebook outputs
- Add gitleaks to both pre-commit and CI (.github/workflows/gitleaks.yml) so hardcoded tokens / private keys are blocked at commit time and on every PR, with a weekly scheduled full-history scan. - Add nbstripout as a pre-commit hook; this also removes the cluster-path leakage that was baked into cpra_pignn_example.ipynb and cra_pignn_example.ipynb cell outputs. - Strip execution outputs from all notebooks under examples/ and notebooks/ as a one-time backfill; future commits will stay clean thanks to the hook. - Document the new "Secrets" section in CONTRIBUTING.md so contributors know where HF tokens belong (HUGGINGFACE_HUB_TOKEN env var). - Fixups by the existing hooks: end-of-file-fixer on .gitignore, a stray trailing whitespace in docs/verification.md. Made-with: Cursor
1 parent d69ac6b commit 55d8f45

18 files changed

Lines changed: 288 additions & 818 deletions

.github/workflows/gitleaks.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Secret scan
2+
3+
# Defence-in-depth secret scanning. pre-commit runs gitleaks locally, this
4+
# workflow re-runs it on the server so a PR from a contributor who skipped
5+
# pre-commit (or disabled the hook) is still caught before merge.
6+
7+
on:
8+
push:
9+
branches: [main]
10+
pull_request:
11+
branches: [main]
12+
schedule:
13+
# Weekly full-history scan, catches secrets accidentally committed on
14+
# an out-of-band branch that never hit a PR.
15+
- cron: "0 6 * * 1"
16+
workflow_dispatch:
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
gitleaks:
23+
name: gitleaks
24+
runs-on: ubuntu-latest
25+
steps:
26+
- uses: actions/checkout@v4
27+
with:
28+
# Full history so we scan the entire commit graph, not just the
29+
# pushed-diff.
30+
fetch-depth: 0
31+
32+
- uses: gitleaks/gitleaks-action@v2
33+
env:
34+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,3 @@ bench_results/
4646

4747
# Streamlit cache
4848
.streamlit/secrets.toml
49-

.pre-commit-config.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,20 @@ repos:
1717
- id: ruff-check
1818
args: [--fix]
1919
- id: ruff-format
20+
21+
# Block commits that introduce API tokens / private keys / other secrets.
22+
# CI re-runs the same check in .github/workflows/gitleaks.yml, so a
23+
# contributor who skips pre-commit locally is still caught on the PR.
24+
- repo: https://github.com/gitleaks/gitleaks
25+
rev: v8.21.2
26+
hooks:
27+
- id: gitleaks
28+
29+
# Strip notebook cell outputs (execution counts, stdout/stderr, rendered
30+
# PNG/HTML) before they hit the index. Without this hook, notebooks tend
31+
# to leak local paths, experiment numbers and occasionally credentials
32+
# via their cached stdout.
33+
- repo: https://github.com/kynan/nbstripout
34+
rev: 0.8.1
35+
hooks:
36+
- id: nbstripout

CONTRIBUTING.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ uv run ruff check src tests scripts app
4949
uv run ruff format src tests scripts app
5050
```
5151

52+
## Secrets
53+
54+
- **Never commit API tokens, private keys, or `.env` files.** The
55+
pre-commit config runs [`gitleaks`](https://github.com/gitleaks/gitleaks)
56+
and [`nbstripout`](https://github.com/kynan/nbstripout) on every
57+
commit, and the `Secret scan` GitHub Actions workflow re-runs
58+
`gitleaks` on every PR plus weekly against the full history.
59+
- Hugging Face tokens belong in the `HUGGINGFACE_HUB_TOKEN` (or
60+
`HF_TOKEN`) environment variable, not in source files or notebook
61+
cells. `scripts/setup_benchmarks.sh` already expects this.
62+
5263
## Quick commands (Makefile)
5364

5465
The `Makefile` wraps the exact commands CI runs:

docs/verification.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
_Generated by `scripts/verify_all_problems.py` on 2026-04-18 22:25:08_
66

7-
This report runs QQA on every built-in problem and compares its best objective against a ground truth or a strong baseline. Each block contains the reference used, per-instance numbers, runtime, and a
7+
This report runs QQA on every built-in problem and compares its best objective against a ground truth or a strong baseline. Each block contains the reference used, per-instance numbers, runtime, and a
88
boolean `ok` flag that must hold for the sweep to be considered successful.
99

1010
## Maximum Independent Set

examples/00_colab_quickstart.ipynb

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "markdown",
5-
"id": "254b20b3a8fd",
5+
"id": "0",
66
"metadata": {},
77
"source": [
88
"# QQA 00 – Colab quickstart\n",
@@ -15,7 +15,7 @@
1515
{
1616
"cell_type": "code",
1717
"execution_count": null,
18-
"id": "6a4fe4199e10",
18+
"id": "1",
1919
"metadata": {},
2020
"outputs": [],
2121
"source": [
@@ -37,15 +37,15 @@
3737
},
3838
{
3939
"cell_type": "markdown",
40-
"id": "7347ef8775b1",
40+
"id": "2",
4141
"metadata": {},
4242
"source": [
4343
"This notebook walks through every problem family shipped with QQA on Google Colab. It installs `qqa` **from PyPI**, detects CUDA if available, and runs a small `qqa.anneal` job per problem with an inline `viz.plot_history` / `viz.plot_best_trajectory` figure. The whole notebook finishes in ~2 minutes on a free CPU Colab runtime and ~30s on a GPU runtime. Set `QQA_INSTALL_FROM_GIT=1` before the install cell to track the `main` branch instead."
4444
]
4545
},
4646
{
4747
"cell_type": "markdown",
48-
"id": "6a4108e36a7c",
48+
"id": "3",
4949
"metadata": {},
5050
"source": [
5151
"## Setup"
@@ -54,7 +54,7 @@
5454
{
5555
"cell_type": "code",
5656
"execution_count": null,
57-
"id": "0a4c2405e5c1",
57+
"id": "4",
5858
"metadata": {},
5959
"outputs": [],
6060
"source": [
@@ -73,7 +73,7 @@
7373
},
7474
{
7575
"cell_type": "markdown",
76-
"id": "a1d6b65223af",
76+
"id": "5",
7777
"metadata": {},
7878
"source": [
7979
"## 1. Maximum Independent Set"
@@ -82,7 +82,7 @@
8282
{
8383
"cell_type": "code",
8484
"execution_count": null,
85-
"id": "166cc91b9c5c",
85+
"id": "6",
8686
"metadata": {},
8787
"outputs": [],
8888
"source": [
@@ -95,7 +95,7 @@
9595
},
9696
{
9797
"cell_type": "markdown",
98-
"id": "71a6c816406c",
98+
"id": "7",
9999
"metadata": {},
100100
"source": [
101101
"## 2. Graph coloring (K=3)"
@@ -104,7 +104,7 @@
104104
{
105105
"cell_type": "code",
106106
"execution_count": null,
107-
"id": "cc306eed64e7",
107+
"id": "8",
108108
"metadata": {},
109109
"outputs": [],
110110
"source": [
@@ -117,7 +117,7 @@
117117
},
118118
{
119119
"cell_type": "markdown",
120-
"id": "bb0aaea6378f",
120+
"id": "9",
121121
"metadata": {},
122122
"source": [
123123
"## 3. Max-Cut"
@@ -126,7 +126,7 @@
126126
{
127127
"cell_type": "code",
128128
"execution_count": null,
129-
"id": "2ff71834e1dc",
129+
"id": "10",
130130
"metadata": {},
131131
"outputs": [],
132132
"source": [
@@ -139,7 +139,7 @@
139139
},
140140
{
141141
"cell_type": "markdown",
142-
"id": "62e409402b24",
142+
"id": "11",
143143
"metadata": {},
144144
"source": [
145145
"## 4. 1D Ising ferromagnet"
@@ -148,7 +148,7 @@
148148
{
149149
"cell_type": "code",
150150
"execution_count": null,
151-
"id": "707bc9b62ee6",
151+
"id": "12",
152152
"metadata": {},
153153
"outputs": [],
154154
"source": [
@@ -160,7 +160,7 @@
160160
},
161161
{
162162
"cell_type": "markdown",
163-
"id": "cb008d11d283",
163+
"id": "13",
164164
"metadata": {},
165165
"source": [
166166
"## 5. Edwards–Anderson 3D spin glass"
@@ -169,7 +169,7 @@
169169
{
170170
"cell_type": "code",
171171
"execution_count": null,
172-
"id": "54542447a433",
172+
"id": "14",
173173
"metadata": {},
174174
"outputs": [],
175175
"source": [
@@ -181,7 +181,7 @@
181181
},
182182
{
183183
"cell_type": "markdown",
184-
"id": "161618c1dbdb",
184+
"id": "15",
185185
"metadata": {},
186186
"source": [
187187
"## 6. Sherrington–Kirkpatrick"
@@ -190,7 +190,7 @@
190190
{
191191
"cell_type": "code",
192192
"execution_count": null,
193-
"id": "2b8b0b0065f3",
193+
"id": "16",
194194
"metadata": {},
195195
"outputs": [],
196196
"source": [
@@ -202,7 +202,7 @@
202202
},
203203
{
204204
"cell_type": "markdown",
205-
"id": "3c2f70df5e53",
205+
"id": "17",
206206
"metadata": {},
207207
"source": [
208208
"## 7. Binary perceptron"
@@ -211,7 +211,7 @@
211211
{
212212
"cell_type": "code",
213213
"execution_count": null,
214-
"id": "e5b1096ad856",
214+
"id": "18",
215215
"metadata": {},
216216
"outputs": [],
217217
"source": [
@@ -224,7 +224,7 @@
224224
},
225225
{
226226
"cell_type": "markdown",
227-
"id": "398b3702283e",
227+
"id": "19",
228228
"metadata": {},
229229
"source": [
230230
"## 8. Hopfield memory"
@@ -233,7 +233,7 @@
233233
{
234234
"cell_type": "code",
235235
"execution_count": null,
236-
"id": "171b957c9c18",
236+
"id": "20",
237237
"metadata": {},
238238
"outputs": [],
239239
"source": [
@@ -247,7 +247,7 @@
247247
},
248248
{
249249
"cell_type": "markdown",
250-
"id": "af78ffc7c942",
250+
"id": "21",
251251
"metadata": {},
252252
"source": [
253253
"## 9. Parallel MIS (`MaximumIndependentSetInstance`)"
@@ -256,7 +256,7 @@
256256
{
257257
"cell_type": "code",
258258
"execution_count": null,
259-
"id": "66c9ce81ac03",
259+
"id": "22",
260260
"metadata": {},
261261
"outputs": [],
262262
"source": [
@@ -270,7 +270,7 @@
270270
},
271271
{
272272
"cell_type": "markdown",
273-
"id": "91f1cffb4dd9",
273+
"id": "23",
274274
"metadata": {},
275275
"source": [
276276
"## Custom loss via `UserProblem`"
@@ -279,7 +279,7 @@
279279
{
280280
"cell_type": "code",
281281
"execution_count": null,
282-
"id": "232fa66b0632",
282+
"id": "24",
283283
"metadata": {},
284284
"outputs": [],
285285
"source": [

0 commit comments

Comments
 (0)