Automate Docker container image updates
This report summarizes scanner evidence for nicholas-fedor/watchtower, a Go project with 4,760 GitHub stars. SynthScan examined 191,876 lines of code across 713 source files, recording 664 pattern matches distributed across 8 syntactic categories. The legacy adjusted pattern signal is 4.0 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 622 finding(s).
Are imports declared and package/API names verified? 2 finding(s).
Are wrappers, guards, and repeated structures necessary? 40 finding(s).
Which changes need focused human review? 664 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 664 distinct pattern matches across 8 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | main.go | 1 | // @title Watchtower HTTP API | COMMENT |
| LOW | main.go | 21 | // @tag.name health | COMMENT |
| LOW | cmd/notify-upgrade.go | 41 | Short: "Upgrade legacy notification configuration to shoutrrr URLs", | COMMENT |
| LOW | cmd/notify-upgrade.go | 81 | // Parameters: | COMMENT |
| LOW | cmd/notify-upgrade.go | 221 | } | COMMENT |
| LOW | cmd/doc.go | 1 | // Package cmd defines Watchtower's command-line interface. | COMMENT |
| LOW | cmd/root.go | 41 | // | COMMENT |
| LOW | cmd/root.go | 61 | var ( | COMMENT |
| LOW | cmd/root.go | 81 | // notifier is the notification system instance responsible for sending update status messages to configured channels. | COMMENT |
| LOW | cmd/root.go | 101 | // restart policy, validating restarts, and cleaning up excess instances. | COMMENT |
| LOW | cmd/root.go | 121 | COMMENT | |
| LOW | cmd/root.go | 181 | // Returns: | COMMENT |
| LOW | cmd/root.go | 201 | // PreRunE and RunE are wired in Execute with a logger-capturing process instance so the | COMMENT |
| LOW | cmd/root.go | 221 | // Parameters: | COMMENT |
| LOW | cmd/root.go | 261 | os.Exit(exitErr.code) | COMMENT |
| LOW | cmd/root.go | 381 | currentWatchtowerContainerID, detectErr = containerClient.GetCurrentContainerID(p.log, ctx, processFs, client) | COMMENT |
| LOW | cmd/root.go | 601 | // - cfg: The RunConfig struct containing filter, API, and mode parameters for this execution. | COMMENT |
| LOW | tools/tplprev/internal/preview/render.go | 41 | // | COMMENT |
| LOW | tools/tplprev/internal/report/id.go | 21 | // ShortID returns the 12-character short version of a container ID. | COMMENT |
| LOW | tools/tplprev/internal/metadata/metadata.go | 1 | // Package metadata holds compile-time build information for tplprev. | COMMENT |
| LOW | internal/settings/flags_test.go | 21 | COMMENT | |
| LOW | internal/settings/config.go | 21 | // Each field is a domain group aligned with internal/settings/flags/<domain> registration. | COMMENT |
| LOW | internal/settings/precedence_test.go | 41 | require.NoError(t, err) | COMMENT |
| LOW | internal/settings/load_test.go | 21 | ) | COMMENT |
| LOW | internal/settings/flags.go | 41 | // errNotSliceValue indicates a flag does not support slice values for appending. | COMMENT |
| LOW | internal/settings/flags.go | 161 | // - error: Non-nil if set fails, nil otherwise. | COMMENT |
| LOW | internal/settings/flags.go | 281 | Str("flag", secret). | COMMENT |
| LOW | internal/settings/flags.go | 381 | return !errors.Is(err, os.ErrNotExist) | COMMENT |
| LOW | internal/settings/doc.go | 1 | // Package settings declares Watchtower's command-line flags and resolves them | COMMENT |
| LOW | internal/settings/viper_get.go | 21 | // durationValue reads a duration from Viper with bare-second env support. | COMMENT |
| LOW | internal/settings/viper_get.go | 81 | return checkNonNegative(name, d) | COMMENT |
| LOW | internal/settings/viper_get.go | 101 | return 0, fmt.Errorf("%s %w, got %s", name, errNegativeDurationSetting, d) | COMMENT |
| LOW | internal/settings/viper_get.go | 121 | return 0, fmt.Errorf("parse bare seconds: %w", err) | COMMENT |
| LOW | internal/settings/bind.go | 21 | ) | COMMENT |
| LOW | internal/settings/load.go | 61 | // GetSecretsFromFiles before Load. Load does not re-parse CLI arguments. | COMMENT |
| LOW | internal/settings/load.go | 221 | EphemeralSelfUpdate: vCfg.GetBool("ephemeral-self-update"), | COMMENT |
| LOW | internal/settings/run_config.go | 21 | type RunConfigInput struct { | COMMENT |
| LOW | internal/settings/flags/spec/register.go | 41 | // - flagSet: Target flag set that receives the registered flags. | COMMENT |
| LOW | internal/settings/flags/spec/spec.go | 41 | // Default must be the static default (not env-baked). EnvKeys lists explicit | COMMENT |
| LOW | internal/settings/flags/spec/doc.go | 1 | // Package spec defines the flag metadata shared by the domain flag packages. | COMMENT |
| LOW | internal/settings/flags/utils/listparse.go | 41 | func SplitCommaOrSpace(value string) []string { | COMMENT |
| LOW | internal/settings/config/notify/notify.go | 1 | package notify | COMMENT |
| LOW | internal/settings/config/notify/notify.go | 21 | TemplateFile string | COMMENT |
| LOW | internal/settings/config/notify/notify.go | 41 | // (--notification-title-tag / WATCHTOWER_NOTIFICATION_TITLE_TAG). | COMMENT |
| LOW | internal/settings/config/update/update.go | 1 | package update | COMMENT |
| LOW | internal/settings/config/update/update.go | 21 | // MonitorOnly monitors for new images without updating containers | COMMENT |
| LOW | internal/settings/config/api/endpoints.go | 61 | // Empty reports whether or not the map of enabled endpoints is empty. | COMMENT |
| LOW | internal/settings/config/api/endpoints.go | 121 | } | COMMENT |
| LOW | internal/settings/config/api/endpoints.go | 181 | parts = append(parts, name) | COMMENT |
| LOW | internal/settings/config/api/endpoints.go | 201 | // - legacyUpdate: Legacy http-api-update. | COMMENT |
| LOW | internal/settings/config/client/client.go | 1 | package client | COMMENT |
| LOW | internal/settings/config/git/git.go | 61 | ComposeProjects map[string]string | COMMENT |
| LOW | internal/settings/config/git/git.go | 161 | COMMENT | |
| LOW | internal/settings/units/duration.go | 21 | errInvalidUnit = errors.New("invalid unit in duration string") | COMMENT |
| LOW | internal/settings/units/duration.go | 101 | COMMENT | |
| LOW | internal/settings/units/duration.go | 201 | return true | COMMENT |
| LOW | internal/settings/units/doc.go | 1 | // Package units parses and formats the duration and disk-space values that | COMMENT |
| LOW | internal/settings/units/diskspace.go | 61 | "tib": tebibyteMultiplier, | COMMENT |
| LOW | internal/settings/units/diskspace.go | 101 | return 0, fmt.Errorf("invalid disk space %q: %w", size, err) | COMMENT |
| LOW | internal/settings/units/diskspace.go | 161 | // point. | COMMENT |
| 547 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | cliff.toml | 9 | # ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | cliff.toml | 12 | # ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | cliff.toml | 23 | # ────────────────────────────────────────────────────────────── | STRING |
| MEDIUM | cliff.toml | 28 | # ────────────────────────────────────────────────────────────── | STRING |
| MEDIUM | cliff.toml | 64 | # ────────────────────────────────────────────────────────────── | STRING |
| MEDIUM | cliff.toml | 68 | # ────────────────────────────────────────────────────────────── | STRING |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 6 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 8 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 15 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 17 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 23 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 25 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 30 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 32 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 38 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 40 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 70 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 72 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 76 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 78 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 95 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 97 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 115 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 117 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 123 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM⚡ | examples/lifecycle-hooks/synology-stop/synology-stop.sh | 125 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 7 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 9 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 44 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 46 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 70 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 72 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 116 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 118 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 148 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 150 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 180 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 182 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 221 | # ------------------------------------------------------------------ | COMMENT |
| MEDIUM | …lifecycle-hooks/synology-stop/test_synology_parsing.sh | 223 | # ------------------------------------------------------------------ | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | internal/settings/flags_test.go | 1187 | // Step 1: env bridge sets pflag to the file path | COMMENT |
| LOW⚡ | internal/settings/flags_test.go | 1199 | // Step 2: secret expansion replaces content and marks Changed=true | COMMENT |
| LOW⚡ | internal/settings/flags_test.go | 1208 | // Step 3: re-running ApplyEnvToFlags must not overwrite the expanded value | COMMENT |
| LOW | docs/http-api/configuration/tls/index.md | 27 | ### Step 1: Obtain a Certificate and Private Key | COMMENT |
| LOW | docs/http-api/configuration/tls/index.md | 59 | ### Step 2: Prepare Files for the Container | COMMENT |
| LOW | docs/http-api/configuration/tls/index.md | 70 | ### Step 3: Mount and Configure Watchtower | COMMENT |
| LOW | docs/http-api/configuration/tls/index.md | 110 | ### Step 4: Connect Using HTTPS | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | internal/settings/flags_test.go | 1187 | // Step 1: env bridge sets pflag to the file path | COMMENT |
| LOW⚡ | internal/settings/flags_test.go | 1199 | // Step 2: secret expansion replaces content and marks Changed=true | COMMENT |
| LOW⚡ | internal/settings/flags_test.go | 1208 | // Step 3: re-running ApplyEnvToFlags must not overwrite the expanded value | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | pkg/notifications/shoutrrr_fuzz_test.go | 16 | // FuzzGetShoutrrrTemplate fuzzes the getShoutrrrTemplate function to ensure robust parsing of template strings. | COMMENT |
| MEDIUM | pkg/notifications/shoutrrr_fuzz_test.go | 34 | // FuzzSanitizeURLForLogging fuzzes the sanitizeURLForLogging function to ensure robust URL parsing. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | test/scripts/test_tls_integration.sh | 52 | # Check if certs exist | COMMENT |
| LOW | .github/workflows/release-nightly.yaml | 69 | # Check if there are any changes in the watched paths since last successful nightly run | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | scripts/docker-util.sh | 2 | # This file is meant to be sourced into other scripts and contain some utility functions for docker e2e testing | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | cmd/notify_upgrade_test.go | 123 | "--notification-email-to", "admin@example.com", | CODE |
| LOW | pkg/notifications/email_test.go | 35 | To: "admin@example.com", | CODE |