feat(ci): add hadolint, markdownlint, and kubescape gates - #4846
Draft
Tanguille wants to merge 2 commits into
Draft
feat(ci): add hadolint, markdownlint, and kubescape gates#4846Tanguille wants to merge 2 commits into
Tanguille wants to merge 2 commits into
Conversation
Adds a Shell Lint workflow (shellcheck + shfmt via mise, excluding archive/) that runs on push/PR touching any *.sh, .editorconfig, or the workflow itself. Pin shfmt 3.13.1 (mvdan/sh) in .mise.toml and mise.lock. Formats the five non-archive shell scripts to shfmt style so the whole-repo gate is green from day one: - validate-pr.sh: &>/dev/null -> &>/dev/null, > /dev/null -> >/dev/null - nextcloud cron.sh / post-start.sh: 2-space -> 4-space indentation - talos-kernel-build.sh: split compound one-liners, redirect spacing - talos-template-vars.sh: 4-space indentation, line wrapping
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@@ data.cron.sh @@
# v1/ConfigMap/default/nextcloud-scripts
! ± value change in multiline text (twelve inserts, twelve deletions)
#!/bin/bash
set -u
# Change to Nextcloud directory (required for occ commands)
- cd /var/www/html || { echo "ERROR: Cannot cd to /var/www/html" >&2; exit 1; }
+ cd /var/www/html || {
+ echo "ERROR: Cannot cd to /var/www/html" >&2
+ exit 1
+ }
# Helper function to run occ commands with error handling
run_occ() {
- local cmd="$1"
- local warning_msg="${2:-${cmd} failed}"
- php occ "$cmd" || echo "WARNING: $warning_msg" >&2
+ local cmd="$1"
+ local warning_msg="${2:-${cmd} failed}"
+ php occ "$cmd" || echo "WARNING: $warning_msg" >&2
}
# Helper function to check if an app is installed
app_installed() {
- echo "$INSTALLED_APPS" | grep -q "$1"
+ echo "$INSTALLED_APPS" | grep -q "$1"
}
# Helper function to run occ command if app is installed
run_if_app_installed() {
- local app="$1"
- local cmd="$2"
- local msg="${3:-Running $app operation...}"
- if app_installed "$app"; then
- echo "$msg"
- run_occ "$cmd"
- fi
+ local app="$1"
+ local cmd="$2"
+ local msg="${3:-Running $app operation...}"
+ if app_installed "$app"; then
+ echo "$msg"
+ run_occ "$cmd"
+ fi
}
echo "Starting Nextcloud cron job at $(date)"
# Not run_occ: it swallows the exit code, so the guard could never fire
if ! php occ status >/dev/null 2>&1; then
- echo "WARNING: Nextcloud not ready, skipping cron job" >&2
- exit 0
+ echo "WARNING: Nextcloud not ready, skipping cron job" >&2
+ exit 0
fi
# Cached once: each `occ` call is a full Nextcloud bootstrap
INSTALLED_APPS="$(php occ app:list)"
# Run standard Nextcloud cron (every 5 minutes)
# This is the main cron job that Nextcloud requires
if ! php -f /var/www/html/cron.php; then
- echo "ERROR: Nextcloud cron.php failed" >&2
- # Don't exit - allow maintenance operations to run even if cron.php fails
+ echo "ERROR: Nextcloud cron.php failed" >&2
+ # Don't exit - allow maintenance operations to run even if cron.php fails
fi
# Run maintenance operations based on time
# Note: Container timezone may be UTC, adjust hour accordingly
[two lines unchanged)]
DAY_OF_WEEK=$(date +%u)
# Run database maintenance and cleanup every hour (at minute 0)
if [ "$MINUTE" = "00" ]; then
- echo "Running hourly maintenance operations..."
- run_occ "db:add-missing-indices"
- run_occ "db:add-missing-primary-keys"
- run_occ "db:add-missing-columns"
- run_occ "files:cleanup"
+ echo "Running hourly maintenance operations..."
+ run_occ "db:add-missing-indices"
+ run_occ "db:add-missing-primary-keys"
+ run_occ "db:add-missing-columns"
+ run_occ "files:cleanup"
fi
# Run very expensive operations less frequently (once per day at 2 AM UTC)
# files:scan --all is VERY expensive and can take a long time
# Adjust the hour if needed (0-23) - note this is UTC time
if [ "$MINUTE" = "00" ] && [ "$HOUR" = "02" ]; then
- echo "Running daily expensive maintenance operations..."
- run_occ "maintenance:repair --include-expensive"
- run_occ "files:scan --all"
- run_if_app_installed "memories" "memories:index" "Running Memories indexing..."
+ echo "Running daily expensive maintenance operations..."
+ run_occ "maintenance:repair --include-expensive"
+ run_occ "files:scan --all"
+ run_if_app_installed "memories" "memories:index" "Running Memories indexing..."
fi
# Run Memories places setup weekly (Sunday at 3 AM UTC)
if [ "$MINUTE" = "00" ] && [ "$HOUR" = "03" ] && [ "$DAY_OF_WEEK" = "7" ]; then
- run_if_app_installed "memories" "memories:places-setup" "Running Memories places setup..."
+ run_if_app_installed "memories" "memories:places-setup" "Running Memories places setup..."
fi
# Run Recognize face clustering weekly (Sunday at 4 AM UTC)
# This is expensive and should run after Memories places setup
if [ "$MINUTE" = "00" ] && [ "$HOUR" = "04" ] && [ "$DAY_OF_WEEK" = "7" ]; then
- run_if_app_installed "recognize" "recognize:cluster-faces" "Running Recognize face clustering..."
+ run_if_app_installed "recognize" "recognize:cluster-faces" "Running Recognize face clustering..."
fi
# Run Recognize background job (every 5 minutes to process queued files)
# This processes face recognition, object detection, landmark recognition, and audio tagging queues
[six lines unchanged)]
# Manual sorting/naming is preserved - the app won't overwrite manually configured faces
# The job will stop after 15 minutes (timeout) and continue in the next run
# This distributes the load and prevents the job from running indefinitely
if [ "$((MINUTE % 15))" = "0" ]; then
- if app_installed "facerecognition"; then
- echo "Running Face Recognition background job (will stop after 15 minutes)..."
- # The app has internal locking (LockTask) to prevent concurrent execution
- # If a previous job is still running, this will fail gracefully due to the lock
- run_occ "face:background_job" "face:background_job failed (may be locked by another instance)"
- fi
+ if app_installed "facerecognition"; then
+ echo "Running Face Recognition background job (will stop after 15 minutes)..."
+ # The app has internal locking (LockTask) to prevent concurrent execution
+ # If a previous job is still running, this will fail gracefully due to the lock
+ run_occ "face:background_job" "face:background_job failed (may be locked by another instance)"
+ fi
fi
# Run Face Recognition album sync (every hour at minute 15)
# This syncs photo albums in the Photos app with recognized faces
# Albums are editable in Photos app, but changes are reverted on next sync
if [ "$MINUTE" = "15" ]; then
- run_if_app_installed "facerecognition" "face:sync-albums" "Running Face Recognition album sync..."
+ run_if_app_installed "facerecognition" "face:sync-albums" "Running Face Recognition album sync..."
fi
echo "Nextcloud cron job completed at $(date)"
@@ data.post-start.sh @@
# v1/ConfigMap/default/nextcloud-scripts
! ± value change in multiline text (nine inserts, ten deletions)
#!/bin/bash
set -u
LOG_FILE="/var/log/post-start.log"
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
log() {
- local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
- echo "$*"
- echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
+ local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
+ echo "$*"
+ echo "$msg" >>"$LOG_FILE" 2>/dev/null || true
}
run_occ() {
- local cmd="cd /var/www/html && php occ"
- for arg in "$@"; do
- cmd="$cmd $(printf '%q' "$arg")"
- done
- su -s /bin/sh www-data -c "$cmd" 2>/dev/null
+ local cmd="cd /var/www/html && php occ"
+ for arg in "$@"; do
+ cmd="$cmd $(printf '%q' "$arg")"
+ done
+ su -s /bin/sh www-data -c "$cmd" 2>/dev/null
}
set_config() {
- local type="$1"
- shift
- # Best effort: a failed config set must not stop the rest. The readiness check below needs
- # run_occ's real exit code, so the tolerance lives here rather than in run_occ.
- run_occ "config:$type:set" "$@" || true
+ local type="$1"
+ shift
+ # Best effort: a failed config set must not stop the rest. The readiness check below needs
+ # run_occ's real exit code, so the tolerance lives here rather than in run_occ.
+ run_occ "config:$type:set" "$@" || true
}
find_tool() {
- local tool="$1"
- local path
- path=$(command -v "$tool" 2>/dev/null)
- [ -n "$path" ] && echo "$path" && return
- find /usr/bin /usr/local/bin -maxdepth 2 -name "$tool" -type f -executable 2>/dev/null | head -1
+ local tool="$1"
+ local path
+ path=$(command -v "$tool" 2>/dev/null)
+ [ -n "$path" ] && echo "$path" && return
+ find /usr/bin /usr/local/bin -maxdepth 2 -name "$tool" -type f -executable 2>/dev/null | head -1
}
log "=== Post-start script started ==="
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq || log "WARNING: apt-get update failed"
for pkg in libimage-exiftool-perl ffmpeg imagemagick libmagickcore-7.q16-10 libmagickwand-7.q16-10 nodejs npm; do
- if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then
- log "Installing $pkg..."
- apt-get install -y --no-install-recommends "$pkg" >/dev/null 2>&1 || log "WARNING: Failed to install $pkg"
- fi
+ if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then
+ log "Installing $pkg..."
+ apt-get install -y --no-install-recommends "$pkg" >/dev/null 2>&1 || log "WARNING: Failed to install $pkg"
+ fi
done
log "Waiting for Nextcloud to be ready..."
ready=0
for i in {1..30}; do
- if run_occ "status" >/dev/null 2>&1; then
- log "Nextcloud is ready"
- ready=1
- break
- fi
- [ "$i" -lt 30 ] && sleep 2
+ if run_occ "status" >/dev/null 2>&1; then
+ log "Nextcloud is ready"
+ ready=1
+ break
+ fi
+ [ "$i" -lt 30 ] && sleep 2
done
[ "$ready" -eq 0 ] && log "WARNING: Nextcloud not ready after 60 seconds"
-
-
log "Configuring tools..."
tool_path=$(find_tool "convert")
[ -n "$tool_path" ] && set_config "system" "preview_imagick_path" --value="$tool_path"
tool_path=$(find_tool "exiftool")
if [ -n "$tool_path" ]; then
- log "Found exiftool at $tool_path"
- set_config "app" "memories exiftool" --value="$tool_path"
+ log "Found exiftool at $tool_path"
+ set_config "app" "memories exiftool" --value="$tool_path"
else
- log "WARNING: exiftool not found"
+ log "WARNING: exiftool not found"
fi
if [ "$ready" -eq 1 ]; then
- set_config "app" "memories enable_transitions" --value="yes"
- set_config "app" "memories preview_max_x" --value="2048"
- set_config "app" "memories preview_max_y" --value="2048"
+ set_config "app" "memories enable_transitions" --value="yes"
+ set_config "app" "memories preview_max_x" --value="2048"
+ set_config "app" "memories preview_max_y" --value="2048"
fi
log "=== Post-start script completed ==="
|
Contributor
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| JavaScript | Sep 5, 2026 2:52a.m. | Review ↗ | |
| Shell | Sep 5, 2026 2:52a.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
Add three CI lint workflows on top of the existing Shell Lint gate: - docker-lint.yaml: hadolint over tracked Dockerfiles (blocking). Add .hadolint.yaml documenting the four rules the talos-kernel build image intentionally deviates from (DL3003 cd-based kernel build, DL3018 build-only source stage, DL3067 whole-toolchain COPY, DL4006 pipe into gpgv for GPG verification of the uncompressed tar). The talos-kernel SPDX heredoc is rewritten as a single python3 -c so the file parses under hadolint's parser, which cannot handle an instruction following a heredoc in a multi-stage build. - markdown-lint.yaml: markdownlint-cli2 over all markdown (blocking). Disable the noisy MD060 table-column-style rule and autofix the remaining 31 issues (27 via --fix, 4 manual fence-language tags). - k8s-scan.yaml: kubescape over kubernetes/ as an advisory report (uploaded as an artifact, not a merge gate). The GitOps tree intentionally runs privileged infrastructure (GPU driver, Ceph, node operators), so the 31 pre-existing High-severity findings are reviewed rather than blocked. zizmor remains the blocking gate for workflow/manifest structure. Pin hadolint 2.15.1, markdownlint-cli2 0.23.2, and kubescape 4.0.13 in .mise.toml and regenerate mise.lock.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Extends the Shell Lint gate with three more CI linters covering the rest of the
repo surface: Dockerfiles, markdown, and the Kubernetes GitOps tree.
hadolintover every tracked Dockerfile.Adds
.hadolint.yamldocumenting the four rules thetalos-kernelbuildimage intentionally deviates from:
DL3003— the kernel Makefile must run with the source tree as CWD, so thecdform is kept (aWORKDIRwould leak into the final stage).DL3018— thesourcestage is build-only (GPG-verifies the kerneltarball); no layer crosses into the image, so pinning apk versions is churn.
DL3067—COPY --from=llvm / /is deliberate: the builder needs thecomplete LLVM toolchain the Sidero tools image provides.
DL4006—xz -cd tar.xz | gpgvpipes because GPG verifies the uncompressedtar; a corrupt stream yields a short/empty input and gpgv fails, so the
&&chain still aborts.markdownlint-cli2over all markdown.Disables the noisy
MD060(table-column-style) rule and autofixes theremaining 31 issues (27 via
--fix, 4 manual fence-language tags).kubescapeoverkubernetes/, uploaded as akubescape-reportartifact. Not a merge gate: the GitOps tree intentionallyruns privileged infrastructure (GPU driver, Ceph, node operators), so the
pre-existing High-severity findings are reviewed in the artifact rather than
blocked.
zizmorremains the blocking gate for workflow/manifest structure.Dockerfile note
The
talos-kernelSPDX block was acat <<EOFheredoc followed by a validationRUNand thenFROM scratch. hadolint's parser cannot handle any instructionfollowing a heredoc in a multi-stage build, so the heredoc is rewritten as a single
python3 -cthat emits the identical SPDX JSON (version interpolated from$KERNEL_VERSION). Output is byte-for-byte equivalent; the following validationRUNstill asserts the file parses.Tooling
Pins
hadolint 2.15.1,markdownlint-cli2 0.23.2, andkubescape 4.0.13in.mise.tomland regeneratesmise.lock. All three new workflows arezizmor-clean.Verification (local, before push)
hadolint(with.hadolint.yaml): 0 findings, exit 0markdownlint-cli2 '**/*.md': 0 issues across 41 fileszizmor --offlineon all three workflows: no findingskubescape scan kubernetes: 145 resources passed / 25 failed (pre-existingHigh findings from intentional infrastructure; report only)
mise fmt --check: clean