feat(harbor): inject mobile-responsive CSS via nginx sub_filter #351

Closed
forgejo_admin wants to merge 2 commits from 345-harbor-mobile-css into main
Contributor

Summary

  • Harbor's Angular UI has no responsive design, making it unusable on mobile devices
  • Injects mobile-responsive CSS into the portal via nginx sub_filter, patching the portal's nginx.conf and mounting a CSS ConfigMap into the portal pod
  • Mobile-first CSS targets ~390px viewports; desktop layout is restored via @media (min-width: 600px)

Changes

  • terraform/modules/harbor/main.tf -- Added kubernetes_config_map_v1.harbor_mobile_css (holds the CSS file), null_resource.harbor_portal_mobile_patch (patches portal ConfigMap with sub_filter directives and deployment with volume mount), and locals block defining the patched nginx.conf and JSON patch payload
  • terraform/modules/harbor/files/mobile.css -- Mobile-first responsive CSS targeting Harbor's Clarity/Ant Design class names: collapsible nav sidebar, scrollable tables, stacked forms, flexible modals, wrapped action bars

Test Plan

  • tofu validate passes (confirmed)
  • tofu apply -target=module.harbor on archbox
  • Verify portal pod restarts with new volume mount (kubectl describe pod -n harbor -l component=portal)
  • Confirm /custom/mobile.css is served: curl -s https://harbor.<domain>/custom/mobile.css
  • Confirm sub_filter injection: curl -s https://harbor.<domain>/ | grep mobile.css
  • Test on 390px mobile viewport: nav collapses, tables scroll, forms stack
  • Test on desktop: layout unchanged from baseline

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • tofu fmt applied
  • tofu validate passes
  • ldraney/pal-e-platform #345 -- Harbor mobile-responsive CSS via nginx sub_filter injection

Closes #345

## Summary - Harbor's Angular UI has no responsive design, making it unusable on mobile devices - Injects mobile-responsive CSS into the portal via nginx sub_filter, patching the portal's nginx.conf and mounting a CSS ConfigMap into the portal pod - Mobile-first CSS targets ~390px viewports; desktop layout is restored via @media (min-width: 600px) ## Changes - `terraform/modules/harbor/main.tf` -- Added `kubernetes_config_map_v1.harbor_mobile_css` (holds the CSS file), `null_resource.harbor_portal_mobile_patch` (patches portal ConfigMap with sub_filter directives and deployment with volume mount), and `locals` block defining the patched nginx.conf and JSON patch payload - `terraform/modules/harbor/files/mobile.css` -- Mobile-first responsive CSS targeting Harbor's Clarity/Ant Design class names: collapsible nav sidebar, scrollable tables, stacked forms, flexible modals, wrapped action bars ## Test Plan - [ ] `tofu validate` passes (confirmed) - [ ] `tofu apply -target=module.harbor` on archbox - [ ] Verify portal pod restarts with new volume mount (`kubectl describe pod -n harbor -l component=portal`) - [ ] Confirm `/custom/mobile.css` is served: `curl -s https://harbor.<domain>/custom/mobile.css` - [ ] Confirm sub_filter injection: `curl -s https://harbor.<domain>/ | grep mobile.css` - [ ] Test on 390px mobile viewport: nav collapses, tables scroll, forms stack - [ ] Test on desktop: layout unchanged from baseline ## Review Checklist - [x] Passed automated review-fix loop - [x] No secrets committed - [x] No unnecessary file changes - [x] Commit messages are descriptive - [x] `tofu fmt` applied - [x] `tofu validate` passes ## Related Notes - `ldraney/pal-e-platform #345` -- Harbor mobile-responsive CSS via nginx sub_filter injection Closes #345
Converts k3s Salt state from verify-only to managed unit file.
Kubelet default of 110 pods was exhausted on single-node archbox
(125 pods, mostly Tailscale proxies). Pillar-driven args allow
future kubelet/server arg changes without editing the service file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix(salt): remove trailing backslash on last ExecStart arg
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline failed
9b4e7dbcb8
QA review caught that the Jinja2 template rendered a continuation
backslash on the final argument line. While systemd tolerates this,
it's technically invalid. Uses loop.last to conditionally omit it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix(ci): replace backticks with printf hex in PR comment script
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline failed
97d8e2f2b7
Woodpecker's shellescape + busybox sh interaction causes triple
backticks in heredoc content to be parsed as command substitution
during trace echo. Uses printf '\x60' to generate fence markers
at runtime, avoiding the shell parsing issue entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Platform SSO initiative: all infrastructure services now authenticate
through the Keycloak platform realm with zero re-login from the admin
dashboard. Includes new pal-e-admin SvelteKit app deployed at
admin.tail5b443a.ts.net with Tailscale funnel.

Services wired:
- Forgejo: declarative gitea.oauth in Helm values (#335)
- Grafana: generic_oauth with auto_login + envFromSecrets (#337)
- Harbor: admin API via null_resource (#338)
- MinIO: Helm chart oidc section (#339)
- Woodpecker: FORGEJO_URL fixed to external + open registration

New admin module: namespace, deployment, service, harbor-creds,
auth secret, and funnel ingress.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat(harbor): inject mobile-responsive CSS via nginx sub_filter
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline failed
e1f15cec79
Harbor's Angular UI lacks responsive design, making it unusable on
mobile devices. This adds a CSS injection pipeline that patches the
portal's nginx.conf with sub_filter to insert a <link> tag for
mobile.css, and mounts the CSS file from a ConfigMap.

Three Terraform resources work together:
- kubernetes_config_map_v1 holds the mobile CSS
- null_resource patches the portal ConfigMap (adds sub_filter directives)
  and deployment (mounts the CSS volume at /usr/share/nginx/html/custom/)
- locals define the patched nginx.conf and JSON patch payload

The CSS is mobile-first: base styles target ~390px viewports with
responsive nav, scrollable tables, stacked forms, and flexible modals.
Desktop layout is restored via @media (min-width: 600px).

Closes #345

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix(harbor): make portal patch idempotent and remove invalid proxy_set_header
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline failed
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
58c1f419ca
Review fixes:
- Remove proxy_set_header Accept-Encoding "" -- invalid in non-proxy
  context (portal serves static files, sub_filter runs before gzip
  in nginx's output filter chain for local content)
- Make deployment patch idempotent by checking for existing mobile-css
  volume and volumeMount before appending, preventing duplicates on
  re-apply

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Contributor

QA Review -- PR #351

Findings

Two issues identified and fixed in commit 58c1f41:

  1. Invalid proxy_set_header in non-proxy context -- The portal nginx serves static files directly, not via proxy_pass. The proxy_set_header Accept-Encoding "" directive is only meaningful in proxy contexts. For locally-served static files, nginx's sub_filter module runs before gzip in the output filter chain, so no decompression workaround is needed. Removed the directive and added a clarifying comment.

  2. Non-idempotent deployment patch -- The JSON patch used "op": "add" with path /- (append), which would create duplicate volume and volumeMount entries if the null_resource triggered again (e.g., CSS content change). Replaced with an idempotent script that checks for existing mobile-css volume and mount before appending.

Verified

  • tofu fmt -- no changes needed
  • tofu validate -- passes
  • No secrets committed
  • No unrelated file changes (only terraform/modules/harbor/main.tf and terraform/modules/harbor/files/mobile.css)
  • $$ escaping correct for HCL heredocs (produces $uri for nginx, $TMPDIR/$NGINX_CONF_JSON for shell)
  • ConfigMap labels consistent with Harbor conventions
  • CSS file uses mobile-first approach with @media (min-width: 600px) desktop restore
  • nginx.conf preserves all original directives from the Helm chart's portal configmap

VERDICT: APPROVE

## QA Review -- PR #351 ### Findings Two issues identified and fixed in commit `58c1f41`: 1. **Invalid `proxy_set_header` in non-proxy context** -- The portal nginx serves static files directly, not via `proxy_pass`. The `proxy_set_header Accept-Encoding ""` directive is only meaningful in proxy contexts. For locally-served static files, nginx's `sub_filter` module runs before gzip in the output filter chain, so no decompression workaround is needed. Removed the directive and added a clarifying comment. 2. **Non-idempotent deployment patch** -- The JSON patch used `"op": "add"` with path `/-` (append), which would create duplicate volume and volumeMount entries if the `null_resource` triggered again (e.g., CSS content change). Replaced with an idempotent script that checks for existing `mobile-css` volume and mount before appending. ### Verified - `tofu fmt` -- no changes needed - `tofu validate` -- passes - No secrets committed - No unrelated file changes (only `terraform/modules/harbor/main.tf` and `terraform/modules/harbor/files/mobile.css`) - `$$` escaping correct for HCL heredocs (produces `$uri` for nginx, `$TMPDIR`/`$NGINX_CONF_JSON` for shell) - ConfigMap labels consistent with Harbor conventions - CSS file uses mobile-first approach with `@media (min-width: 600px)` desktop restore - nginx.conf preserves all original directives from the Helm chart's portal configmap ### VERDICT: APPROVE
forgejo_admin closed this pull request 2026-05-06 02:15:03 +00:00
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline failed
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful

Pull request closed

Sign in to join this conversation.
No description provided.