Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/spotbugs.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
name: SpotBugs

# SpotBugs + FindSecBugs static analysis. Runs on every PR and push
# to main. Fails the build on any HIGH-confidence finding not listed
# in config/spotbugs/exclude.xml (the Phase-9 baseline). SARIF output
# is uploaded to GitHub Code Scanning so findings are visible in the
# Security tab.
# to main. Fails the build on every HIGH-confidence finding. SARIF
# output is uploaded to GitHub Code Scanning so findings are visible
# in the Security tab.

on:
pull_request:
Expand Down
76 changes: 43 additions & 33 deletions BUGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,38 @@ constructing the notification popup singleton on the EDT, making quick-list
spinners instance-owned, clearing SFTP random-access streams before close, and
returning immediately when trash waiting is interrupted.

### 1.60 ~~MED — SpotBugs still has ignored findings after the baseline drawdown~~ **FIXED**
**`barebones-core/.../ThemeCache.java`**,
**`barebones-protocol-nfs/src/main/java/com/sun/`**,
**`sun-net-www/src/main/java/sun/net/www/`**

Phase 20 intentionally left one own-code `MS_MUTABLE_ARRAY` suppression for
`ThemeCache.foregroundColors` / `backgroundColors` and wholesale package
suppressions for the vendored Sun NFS/RPC URL-handler code. That means
SpotBugs can still report green while hiding known findings.

Phase 33 is removing the filter instead of carrying another exception: the
theme arrays are being made private with typed hot-path accessors, and the
vendored package findings are being surfaced so they can be fixed or proven
obsolete by the actual SpotBugs run.

The first unfiltered run fails only in `sun-net-www` and
`barebones-protocol-nfs`: 5 URL-handler findings
(`ES_COMPARING_PARAMETER_STRING_WITH_EQ`, `PATH_TRAVERSAL_IN`,
`ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD`, `NM_SAME_SIMPLE_NAME_AS_SUPERCLASS`)
and 29 NFS/RPC/GSS/XFile findings covering default charset use,
missing `hashCode()`, lazy static initialization, ignored close/flush
failures, an impossible chooser cast, and one same-simple-name warning.

Phase 33 fixes the last own-code mutable-array exposure by making the
`ThemeCache` color arrays private and routing renderer reads through typed
accessors. It also fixes the surfaced vendored findings directly: deterministic
charsets, matching `hashCode()` implementations, synchronized/default static
initialization, explicit exception propagation or thread interrupt handling,
the chooser property-type bug, and compatibility wrapper classes for the two
same-simple-name reports. The SpotBugs exclude filter has been deleted; the
unfiltered `spotbugsMain spotbugsTest` run is green.

---

## 2. UX gaps
Expand Down Expand Up @@ -1067,12 +1099,11 @@ discovery does the wiring; others use `api` / `implementation`.
The convention isn't documented; the pattern flips around Phase
boundaries. Worth a written convention.

### 5.12 SpotBugs baseline is technical debt with no decay schedule
`config/spotbugs/exclude.xml` had 95 entries at Phase 9; we burned
one in Phase 12 (`XORCipher`) and added zero new entries since.
A target like "drop 5 entries per release" would force the file to
shrink. 62 of the entries are real bugs in our own code waiting
for someone to fix them.
### 5.12 ~~SpotBugs baseline is technical debt with no decay schedule~~ **DONE**
Phase 33 deleted the SpotBugs exclude filter after fixing the last own-code
mutable-array exposure and the vendored Sun NFS/RPC URL-handler findings that
the package filters had hidden. SpotBugs now fails on every high-confidence
finding.

---

Expand Down Expand Up @@ -1123,33 +1154,12 @@ The mount-helper module was removed in PR #24.
Single source of truth for the 30+ scattered timeout/poll
constants noted in 5.10. Optional override via system property.

### 6.10 SpotBugs baseline drawdown phase
A dedicated short PR that picks one bug pattern (e.g. all 8
remaining `HE_EQUALS_USE_HASHCODE` entries) and fixes them
properly + removes the corresponding lines from `exclude.xml`.
Repeat until the file is empty.
### 6.10 ~~SpotBugs baseline drawdown phase~~ **DONE**
Phase 33 completed the drawdown: there is no SpotBugs exclude filter left.

---

## 7. SpotBugs baseline summary (carried over from Phase 9)

`config/spotbugs/exclude.xml` currently suppresses **~94** findings
across our own code + vendored upstream:

| Bucket | Count | Notes |
|--------|------:|-------|
| `DM_DEFAULT_ENCODING` | 41 | Charset-default reliance — most are in widget / dialog / archive code paths. |
| `ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD` | 15 | Form-state caches; the Phase-10b/-11 panels avoid this via the `LastValues` holder pattern. |
| `HE_EQUALS_USE_HASHCODE` | 8 | Real bugs (see 1.9). |
| `DMI_RANDOM_USED_ONLY_ONCE` | 5 | Each `new Random()` for a single nextInt; trivial to fix. |
| `MS_SHOULD_BE_FINAL` | 4 | Mutable static fields. |
| `DE_MIGHT_IGNORE` | 3 | Catch-and-ignore exception types. |
| `NM_SAME_SIMPLE_NAME_AS_SUPERCLASS` | 3 | Name shadowing across packages. |
| `MS_MUTABLE_ARRAY` | 2 | Static `byte[]` exposed. |
| `ES_COMPARING_PARAMETER_STRING_WITH_EQ` | 2 | `==` instead of `.equals()`. |
| `CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE` | 2 | Broken `clone()`. |
| various others | 8 | One each. |
| Vendored (`com.sun.*`, `sun.net.www.*`) | 33 | Wholesale package suppressions; not ours to fix. |

The baseline file's stated lifecycle is "delete a line, fix the
underlying bug, repeat." See refactor proposal 6.10.
## 7. SpotBugs baseline summary

There is no SpotBugs baseline left. Phase 33 removed the project-level exclude
filter and fixed the remaining findings it exposed.
63 changes: 41 additions & 22 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Source: forked from https://github.com/mucommander/mucommander to https://github
| **17** | done | **Concurrency + correctness sweep** — `Hashtable` → `ConcurrentHashMap` (`ActionProperties`); `synchronized` on `CredentialsManager` read-modify-write; `WeakHashMap` listener pseudo-set → `CopyOnWriteArraySet` (`BookmarkManager`); all 33 `barebones-core` empty catches surfaced (try-with-resources for stream close, `AssertionError` for `Cloneable` swallows, restore-interrupt for `InterruptedException`, error dialogs for user-visible failures, WARN logs for cleanup-after-error); `EditBookmarksDialog` no-selection NPE replaced with `IllegalStateException`; principle established: no silent fallbacks in logic | this PR |
| **18** | done | **Observability + logging** — S3 module gains logger fields + WARN on every AWS error, INFO on connection open/close, DEBUG on each list page, INFO on activator register/shutdown; `ThemeManager` save-failure carries theme type/name/file path; AppleScript decoder logs REPLACE-branch substitutions at DEBUG and caps `outputBuffer` at 1 MiB with a visible truncation marker; SFTP auth failures logged at WARN. `System.err` in CLI bootstrap (`Application.printError`, `Main` headless detection) and `EncodingDetector.main` documented as kept-by-design. | this PR |
| **19** | done | **UX polish** — `S3ErrorHandler` typed 401/403/404; error-dialog throwable plumbed through Phase-17 + every `FileJob` error site (~25 catches across 10 job classes); `DynamicList.RemoveAction` prompts before deletion; `FileDropTargetListener` rejects drops on non-writable target folders; `ProgressNotifier` SPI wires producer-side hints into the MainFrame status bar; `S3Object.StatusBarProgressListener` publishes byte-accurate S3 upload progress ("47.3 MiB / 100.0 MiB (47%)") throttled to 250 ms; `CredentialsWriter` posts a status-bar explainer before the first keychain prompt. Default-button focus, huge-file open, folder-browse cursor, prefs Cancel-revert, and batch-rename preview audit-confirmed as already-fixed / as-designed. | this PR |
| **20** | done | **SpotBugs baseline drawdown to ~zero** — fixed every own-code suppression in `config/spotbugs/exclude.xml` (DM_DEFAULT_ENCODING ×17, ST_WRITE_TO_STATIC ×12, DMI_RANDOM_USED_ONLY_ONCE ×4, MS_SHOULD_BE_FINAL ×4, plus 7 one-off patterns). Encoding fixes are explicit, NOT silent UTF-8 fallbacks: CP437 for Zip APPNOTE-spec entries, NPE-on-null for `ZipOutputStream.setEncoding`, `Charset.defaultCharset()` for process I/O, BOMWriter for the text editor's read-encoding round-trip. One suppression remains: `ThemeCache.foregroundColors`/`backgroundColors` MS_MUTABLE_ARRAY — documented architectural tradeoff (per-cell-render hot path). Vendored `com.sun.*` / `sun.net.www.*` package-level suppressions kept. | this PR |
| **20** | done | **SpotBugs baseline drawdown to ~zero** — fixed the legacy own-code SpotBugs baseline entries (DM_DEFAULT_ENCODING ×17, ST_WRITE_TO_STATIC ×12, DMI_RANDOM_USED_ONLY_ONCE ×4, MS_SHOULD_BE_FINAL ×4, plus 7 one-off patterns). Encoding fixes are explicit, NOT silent UTF-8 fallbacks: CP437 for Zip APPNOTE-spec entries, NPE-on-null for `ZipOutputStream.setEncoding`, `Charset.defaultCharset()` for process I/O, BOMWriter for the text editor's read-encoding round-trip. One suppression remained temporarily: `ThemeCache.foregroundColors`/`backgroundColors` MS_MUTABLE_ARRAY. Vendored `com.sun.*` / `sun.net.www.*` package-level suppressions were also kept temporarily. Phase 33 removes that remaining baseline. | this PR |
| **21+** | open | **Architecture refactors — REVIEW REQUIRED.** Tracked separately; do NOT execute without explicit approval per `BUGS.md` §5/§6. | n/a |
| **22** | done | **Modern logging migration** — internal `barebones-logging` facade backed by JDK logging APIs; `--debug` support; SLF4J/logback removed from production dependencies. | landed in #30 |
| **23** | done | **Systematic dependency upgrade pass** — audited every `gradle/libs.versions.toml` entry against Maven Central / Gradle Plugin Portal release metadata; removed `jsr305`; documented major/pre-release pins. | this PR |
Expand All @@ -51,7 +51,8 @@ Source: forked from https://github.com/mucommander/mucommander to https://github
| **29** | done | **JUnit 5 + protocol scope cleanup** — migrate legacy tests to JUnit 5, improve S3 endpoint URL parsing, remove retired-protocol future scope, and evaluate NFSv4 replacement options. | landed in #37 |
| **30** | done | **Architecture refactor batch** — archive format `ServiceLoader`, remove vendored `apache-bzip2`, centralize runtime tunables, and make javac unchecked/deprecation warnings fail the build. | landed in #38 |
| **31** | done | **Repo skill + architecture/docs/check sweep** — add repo-local Java GUI slop cleanup skill, document current architecture, align stale docs/comments with the implementation, and harden CI against fake-green checks. | landed in #39 |
| **32** | in progress | **Repo-wide Java GUI slop sweep** — run the repo-local slop-cleaning skill against current `origin/main`, record each finding in `BUGS.md`, fix actionable issues, and keep continuity docs current. | this PR |
| **32** | done | **Repo-wide Java GUI slop sweep** — run the repo-local slop-cleaning skill against current `origin/main`, record each finding in `BUGS.md`, fix actionable issues, and keep continuity docs current. | landed in #40 |
| **33** | in progress | **Clear remaining ignored SpotBugs findings** — remove the last `ThemeCache` own-code suppression and surface/fix vendored Sun NFS/RPC URL-handler findings so SpotBugs runs without an exclude filter. | this PR |

**Hard rule**: only one branch / one PR is in flight at a time. The user — not the LLM — decides when a PR is ready and when the next one starts. The LLM does not autonomously open new PRs to fan out work in parallel.

Expand Down Expand Up @@ -364,27 +365,25 @@ that's otherwise mechanical.

- Add **SpotBugs + FindSecBugs** as a Gradle-driven CI step
(`.github/workflows/spotbugs.yaml`, PR + push-to-main triggered).
Fails the build on any HIGH-confidence finding not listed in
`config/spotbugs/exclude.xml`. SARIF uploaded to GitHub Code
Scanning.
Fails the build on every HIGH-confidence finding. SARIF uploaded
to GitHub Code Scanning.
- Add **OWASP Dependency-Check** as a scheduled weekly CI run
(`.github/workflows/dependency-check.yaml`, Monday 06:00 UTC +
workflow_dispatch). Fails on CVSS ≥ 7.0 not suppressed in
`config/dependency-check/suppression.xml`. SARIF uploaded to
GitHub Code Scanning.
- The Phase-9 SpotBugs baseline (`config/spotbugs/exclude.xml`)
captures **95 pre-existing HIGH-confidence findings** in the
brownfield muCommander code. Categorisation:
- The Phase-9 SpotBugs baseline captured **95 pre-existing
HIGH-confidence findings** in the brownfield muCommander code.
Categorisation:
* `com.sun.*` / `sun.net.www.*` — vendored upstream (33 findings)
suppressed wholesale via `<Package>` matches.
* Per-(class, bug-pattern) suppressions for our own code (62
findings), each line a real issue to fix in a follow-up.
* Top patterns: `DM_DEFAULT_ENCODING` (charset reliance),
`ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD` (static caches),
`HE_EQUALS_USE_HASHCODE` (broken `equals/hashCode` contract).
- Post-Phase-9 cleanup phases will progressively remove suppressions
from `config/spotbugs/exclude.xml` until empty (then the file can
be deleted and SpotBugs runs purely on regression).
- Phase 33 removed the final baseline and deleted the SpotBugs
exclude filter; SpotBugs now runs purely on regression.

### Phase 12 — Keychain-backed credentials (one PR)

Expand Down Expand Up @@ -1025,20 +1024,19 @@ reassigned them; the `static` exposure was sloppy not load-bearing.
progress <= 100)` — always true. Fixed to `&&` (the obvious
intent).

**Documented suppression kept**:
**Temporary baseline left for Phase 33**:
- `ThemeCache.foregroundColors` / `backgroundColors`
`MS_MUTABLE_ARRAY`: per-cell-render hot path; refactoring to
defensive-copy accessors would be unacceptable overhead. Setters
for the related fields were already extracted in the ST_WRITE
pass; only the array-element writes remain direct (and SpotBugs
doesn't flag those).
`MS_MUTABLE_ARRAY`: the arrays were still public static storage.
- Vendored `com.sun.*` / `sun.net.www.*` package filters still hid
the NFS/RPC URL-handler findings.

**Vendored `com.sun.*` / `sun.net.www.*` package suppressions kept**
— upstream code, not ours to fix.
Phase 33 removed both remainders: the theme arrays are private behind
typed accessors, vendored findings were fixed, and the SpotBugs
exclude filter was deleted.

**Exit criteria** (met): `config/spotbugs/exclude.xml` contains the
vendored packages plus exactly one documented own-code exception;
`./gradlew test spotbugsMain` green.
**Exit criteria** (met): `./gradlew test spotbugsMain` green with the
then-current temporary baseline. Phase 33 supersedes this with a
fully unfiltered SpotBugs run.

### Phase 21+ — Architecture refactors (parking lot)

Expand Down Expand Up @@ -1370,6 +1368,27 @@ compile plus MinIO S3 integration test, `./gradlew cleanTest test
--stacktrace`, and `./gradlew check --stacktrace`. Next work is to commit/push
to PR #40 and watch CI.

### Phase 33 — Clear remaining ignored SpotBugs findings (this PR)

Phase 33 starts from `origin/main` after PR #40 was merged. The active branch is
`phase-33/spotbugs-baseline-drawdown`; no PR was open at branch creation.

Initial findings recorded in `BUGS.md` 1.60:
- the only remaining own-code SpotBugs suppression was
`ThemeCache.foregroundColors` / `backgroundColors` `MS_MUTABLE_ARRAY`;
- the only other suppressions were wholesale vendored Sun NFS/RPC and
URL-handler package filters.

Current status: the theme color arrays are private and direct
renderer/table/tree reads now use tiny typed accessors. The SpotBugs
exclude filter has been removed entirely. The first unfiltered run surfaced
5 `sun-net-www` findings and 29 `barebones-protocol-nfs` findings; those were
fixed without keeping any replacement filter. Local unfiltered
`./gradlew spotbugsMain spotbugsTest --stacktrace` is green.
Follow-up validation also passed with `git diff --check`, `./gradlew cleanTest
test --stacktrace`, and `./gradlew check --stacktrace`. Next work is to commit,
push, open the single Phase 33 PR, and watch CI.

**Exit criteria**: all actionable findings discovered in this sweep are either
fixed or explicitly documented as deferred; local validation includes at least
`./gradlew cleanTest test --stacktrace`, `./gradlew check --stacktrace`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,8 @@ public RecordingKeyStrokeField(KeyStroke currentKeyStroke, DescriptionData descr
setBorder(BorderFactory.createEmptyBorder());
setHorizontalAlignment(JTextField.CENTER);
setEditable(false);
setBackground(ThemeCache.backgroundColors[ThemeCache.ACTIVE][ThemeCache.SELECTED]);
setForeground(ThemeCache.foregroundColors[ThemeCache.ACTIVE][ThemeCache.SELECTED][ThemeCache.PLAIN_FILE]);
setBackground(ThemeCache.backgroundColor(ThemeCache.ACTIVE, ThemeCache.SELECTED));
setForeground(ThemeCache.foregroundColor(ThemeCache.ACTIVE, ThemeCache.SELECTED, ThemeCache.PLAIN_FILE));
addKeyListener(this);
// It is required to disable the traversal keys in order to support keys combination that include the TAB
// key
Expand All @@ -535,7 +535,7 @@ protected void paintBorder(Graphics g) {
paintDottedBorder(g,
getWidth(),
getHeight(),
ThemeCache.backgroundColors[ThemeCache.ACTIVE][ThemeCache.NORMAL]);
ThemeCache.backgroundColor(ThemeCache.ACTIVE, ThemeCache.NORMAL));
}

/////////////////////////////
Expand Down Expand Up @@ -884,7 +884,7 @@ public Component getTableCellRendererComponent(JTable table,

// set cell's foreground color
label.setForeground(
ThemeCache.foregroundColors[ThemeCache.ACTIVE][ThemeCache.NORMAL][ThemeCache.PLAIN_FILE]);
ThemeCache.foregroundColor(ThemeCache.ACTIVE, ThemeCache.NORMAL, ThemeCache.PLAIN_FILE));
}
// Any other column
else {
Expand Down Expand Up @@ -919,17 +919,17 @@ public Component getTableCellRendererComponent(JTable table,
customized = false;
}

label.setForeground(ThemeCache.foregroundColors[ThemeCache.ACTIVE][ThemeCache.NORMAL][customized
label.setForeground(ThemeCache.foregroundColor(ThemeCache.ACTIVE, ThemeCache.NORMAL, customized
? ThemeCache.PLAIN_FILE
: ThemeCache.HIDDEN_FILE]);
: ThemeCache.HIDDEN_FILE));
}
}

// set outline for the focused cell
label.setOutline(hasFocus ? ThemeCache.backgroundColors[ThemeCache.ACTIVE][ThemeCache.SELECTED] : null);
label.setOutline(hasFocus ? ThemeCache.backgroundColor(ThemeCache.ACTIVE, ThemeCache.SELECTED) : null);
// set cell's background color
label.setBackground(ThemeCache.backgroundColors[ThemeCache.ACTIVE][rowIndex % 2 == 0 ? ThemeCache.NORMAL
: ThemeCache.ALTERNATE]);
label.setBackground(ThemeCache.backgroundColor(ThemeCache.ACTIVE, rowIndex % 2 == 0 ? ThemeCache.NORMAL
: ThemeCache.ALTERNATE));

return label;
}
Expand Down
Loading