Skip to content

Commit 34a7481

Browse files
authored
Merge branch 'develop' into fix/reproducibility-audit-findings
2 parents 7931fbe + e7702a9 commit 34a7481

54 files changed

Lines changed: 22571 additions & 1625 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/bullock.yml

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ jobs:
7676
# Write-access gating happens twice: the first step fails fast for
7777
# non-write actors, and claude-code-action enforces it again internally —
7878
# this `if` just avoids spinning a runner on unrelated comments.
79-
if: contains(github.event.comment.body, '@bullock')
79+
# The Bot filter matters because GITHUB_TOKEN comments never retrigger
80+
# workflows (GitHub anti-recursion) but GitHub-App comments DO: a claude.yml
81+
# review quoting "@bullock" from the thread would otherwise spin a runner
82+
# and die red at the access gate — noise on the PR, wasted runner.
83+
if: contains(github.event.comment.body, '@bullock') && github.event.comment.user.type != 'Bot'
8084
runs-on: ubuntu-24.04
8185
# analyze_and_test's checks job needs ~30min for setup + `make checks` alone;
8286
# Bullock adds Claude's implement/verify loop on top of the same prefix.
@@ -213,6 +217,13 @@ jobs:
213217
# format, and Write the verdict sentinel.
214218
- name: Bullock (Claude Code)
215219
if: steps.src.outputs.cross != 'true'
220+
# Step-level timeout on purpose: the job-level 60min timeout CANCELS the
221+
# job, and "Act on Bullock's verdict" is guarded by !cancelled() — so a
222+
# job timeout would be a silent red run with no comment. A step timeout
223+
# merely FAILS this step, which degrades to the no-valid-verdict comment.
224+
# Budget: ~6min gate+setup before this step + 45 here + ~2 of git/PR
225+
# plumbing after stays under the job's 60.
226+
timeout-minutes: 45
216227
uses: anthropics/claude-code-action@v1
217228
with:
218229
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -272,6 +283,7 @@ jobs:
272283
273284
## Step 4 — Implement (ONLY if sufficient)
274285
- Change ONLY what was requested. No opportunistic refactors, no unrelated cleanup.
286+
- NEVER modify anything under `.github/` (workflows, actions, CI config) — the workflow refuses to commit such changes. If the request requires a CI change, treat it as insufficient and say so in "question".
275287
- Follow AGENTS.md strictly: use `fvm`; respect the layer/facade/failure/naming rules; NEVER log or expose secrets (mnemonic/seed/xpriv/PIN); no hardcoded user-facing strings (use `context.loc.*`); no raw colors.
276288
- After editing, format your new/changed Dart files so the CI format gate can't fail on untracked files:
277289
run `fvm dart format` on the files you touched, then `git add -A` for the changed source (do NOT add `.bullock/`).
@@ -319,7 +331,10 @@ jobs:
319331
320332
if [ "$sufficient" != "true" ]; then
321333
body="🐂 Bullock needs more info before implementing:"
322-
body="${body}"$'\n\n'"> ${question:-Please clarify what you'd like changed.}"
334+
# NB: no apostrophes inside ${var:-word} — bash treats a single
335+
# quote there as a quoting char even inside double quotes, which
336+
# made this whole script unparseable (exit 2 at EOF).
337+
body="${body}"$'\n\n'"> ${question:-Please clarify what you would like changed.}"
323338
comment "$body"
324339
echo "Insufficient info — asked for clarification, no PR opened."
325340
exit 0
@@ -329,22 +344,27 @@ jobs:
329344
git config user.name "bullock[bot]"
330345
git config user.email "bullock@users.noreply.github.com"
331346
332-
# GITHUB_TOKEN cannot push changes under .github/workflows/ — the push
333-
# (below) would be rejected AFTER commit, going red with no feedback.
334-
# Bail early with an explanation. This is also a deliberate backstop
335-
# against Bullock modifying its own workflow. `git status --porcelain`
336-
# reports both tracked edits and new untracked files, and is checked
337-
# before staging so a workflow-file change never enters the commit.
338-
if [ -n "$(git status --porcelain -- .github/workflows)" ]; then
339-
comment "🐂 Bullock's changes touch \`.github/workflows/\`, which a bot token isn't allowed to push. Please make workflow changes manually."
340-
echo "Workflow files touched — declined (GITHUB_TOKEN cannot push workflows)."
347+
# ALL of .github/ is off-limits to Bullock, for two distinct reasons:
348+
# - .github/workflows/: GITHUB_TOKEN cannot push these — the push
349+
# (below) would be rejected AFTER commit, going red with no feedback.
350+
# - the rest (.github/actions/ composite, CI config): the token CAN
351+
# push them, but they execute in future CI runs with secrets — a
352+
# prompt-injected change here must be blocked mechanically, not just
353+
# by the prompt's SECURITY section. Bullock has no legitimate reason
354+
# to touch CI; a maintainer changes it manually.
355+
# `git status --porcelain` reports both tracked edits and new
356+
# untracked files, and is checked before staging so a CI-file change
357+
# never enters the commit.
358+
if [ -n "$(git status --porcelain -- .github)" ]; then
359+
comment "🐂 Bullock's changes touch \`.github/\` (workflows or CI config), which Bullock isn't allowed to modify. Please make CI changes manually."
360+
echo "CI files touched — declined (.github/ is off-limits to Bullock)."
341361
exit 0
342362
fi
343363
344364
# Stage only source changes; never sweep the whole tree (build_runner
345365
# drift, make side effects, stray artifacts) into the stacked PR, and
346-
# never stage workflow files (guarded above).
347-
git add -A -- ':(exclude).github/workflows'
366+
# never stage CI files (guarded above).
367+
git add -A -- ':(exclude).github'
348368
349369
if git diff --cached --quiet; then
350370
comment "🐂 Bullock judged the request actionable but produced no changes. Please re-summon with a more specific instruction."

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ CLAUDE.md
115115
# sentry-native build artifacts pulled by sentry_flutter on Linux
116116
.sentry-native/
117117

118-
# Generated integration-test aggregator (see tool/gen_all_test.dart)
118+
# Generated integration-test aggregator (see tools/gen_all_test.dart)
119119
integration_test/all_test.dart
120120

121121
# Generated swap debug log export (written during test runs)

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ Workflow when you need a widget:
171171
3. **If genuinely new and reused by ≥ 2 features**, put it in `lib/core/widgets/<category>/` from the start — that *is* growing the UI Kit.
172172
4. **If used by exactly one feature**, it lives in `<feature>/ui/widgets/` — but write it composable enough to be promoted later (no hardcoded colors, no hardcoded text, take callbacks not bloc refs).
173173
5. **Widgets never live under `adapters/`, `frameworks/`, `domain/`, or `application/`.** UI goes in `ui/` or `lib/core/widgets/`. Full stop.
174-
6. **No hardcoded user-facing strings.** Always `context.loc.<key>` — the `BuildContext` extension (`build_context_x.dart`) that wraps `AppLocalizations.of(context)`; it is the dominant convention (≈2564 uses vs 3 raw `AppLocalizations.of`). Add the key to [`localization/`](localization/) and run `make translations`. A duplicated literal across screens means a missing l10n key.
174+
6. **No hardcoded user-facing strings.** Always `context.loc.<key>` — the `BuildContext` extension (`build_context_x.dart`) that wraps `AppLocalizations.of(context)`; it is the dominant convention (≈2564 uses vs 3 raw `AppLocalizations.of`). Manage keys in [`localization/`](localization/) with [`tools/arb.dart`](tools/README.md) (`fvm dart run tools/arb.dart help`) — don't hand-edit the `.arb` files — then run `make translations`. A duplicated literal across screens means a missing l10n key.
175175
7. **Theme tokens only** — colors, spacing, typography pulled from the theme. See rule #10 above.
176176

177177
When you spot a duplicate of an existing core widget in feature code, flag it in the PR description as a follow-up cleanup. Don't silently leave it. Don't fix unrelated duplicates in the same PR either — that breaks atomic commits.

Containerfile.tools

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,21 @@ RUN fvm install ${FLUTTER_VERSION} --verbose --no-setup
190190
RUN fvm global ${FLUTTER_VERSION}
191191
ENV PATH="/home/$USER/fvm/default/bin:${PATH}"
192192

193+
193194
# Download Android cmdline-tools
194-
RUN sudo wget -q https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS_VERSION}_latest.zip -O /tmp/android-cmdline-tools.zip
195+
# (USER root instead of sudo: setuid binaries are unreliable under rootless
196+
# podman user namespaces — sudo fails with "account validation failure" —
197+
# and are unnecessary at build time since USER switching achieves the same.)
198+
USER root
199+
RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS_VERSION}_latest.zip -O /tmp/android-cmdline-tools.zip
195200

196201
# Set up Android SDK
197-
RUN sudo mkdir -p ${ANDROID_HOME}/cmdline-tools
198-
RUN sudo unzip -q /tmp/android-cmdline-tools.zip -d ${ANDROID_HOME}/cmdline-tools
199-
RUN sudo mv ${ANDROID_HOME}/cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest
200-
RUN sudo rm /tmp/android-cmdline-tools.zip
201-
RUN sudo chown -R $USER ${ANDROID_HOME}
202+
RUN mkdir -p ${ANDROID_HOME}/cmdline-tools
203+
RUN unzip -q /tmp/android-cmdline-tools.zip -d ${ANDROID_HOME}/cmdline-tools
204+
RUN mv ${ANDROID_HOME}/cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest
205+
RUN rm /tmp/android-cmdline-tools.zip
206+
RUN chown -R $USER ${ANDROID_HOME}
207+
USER $USER
202208

203209
# Install Android SDK components
204210
RUN yes | sdkmanager --sdk_root=${ANDROID_HOME} --licenses

integration_test/coins_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import 'package:flutter_test/flutter_test.dart';
3333
// wallet's real UTXOs and asserts the confirmations/labels fields the view
3434
// renders. Needs a funded testnet wallet → skipped when absent.
3535
//
36-
// Run via `make integration-test` (auto-aggregated by tool/gen_all_test.dart).
36+
// Run via `make integration-test` (auto-aggregated by tools/gen_all_test.dart).
3737
Future<void> main({bool isInitialized = false}) async {
3838
TestWidgetsFlutterBinding.ensureInitialized();
3939
if (!isInitialized) await Bull.init();

0 commit comments

Comments
 (0)