{"id":50881793,"url":"https://github.com/validatedpatterns/vp-s4-storage-chart","last_synced_at":"2026-06-15T13:31:18.636Z","repository":{"id":358715618,"uuid":"1242680034","full_name":"validatedpatterns/vp-s4-storage-chart","owner":"validatedpatterns","description":"Validated Patterns Encapsulation of S4 Chart","archived":false,"fork":false,"pushed_at":"2026-05-18T18:43:02.000Z","size":104,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T20:35:06.710Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go Template","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/validatedpatterns.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-18T16:44:46.000Z","updated_at":"2026-05-18T18:41:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/validatedpatterns/vp-s4-storage-chart","commit_stats":null,"previous_names":["validatedpatterns/vp-s4-storage-chart"],"tags_count":1,"template":false,"template_full_name":"validatedpatterns/vp-template-chart","purl":"pkg:github/validatedpatterns/vp-s4-storage-chart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/validatedpatterns%2Fvp-s4-storage-chart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/validatedpatterns%2Fvp-s4-storage-chart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/validatedpatterns%2Fvp-s4-storage-chart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/validatedpatterns%2Fvp-s4-storage-chart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/validatedpatterns","download_url":"https://codeload.github.com/validatedpatterns/vp-s4-storage-chart/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/validatedpatterns%2Fvp-s4-storage-chart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34365596,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-15T13:31:17.593Z","updated_at":"2026-06-15T13:31:18.625Z","avatar_url":"https://github.com/validatedpatterns.png","language":"Go Template","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vp-s4-storage\n\n![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square)\n\nValidated Patterns chart for non-production S4 object storage (dev/demo) with External Secrets and bucket provisioning. For production S3 on OpenShift, use openshift-data-foundations (ODF).\n\nWraps the [S4](https://github.com/rh-aiservices-bu/s4) Helm chart with External Secrets for deployment credentials and imperative Jobs to provision S3 buckets.\n\n\u003e **Not for production.** This chart deploys [S4](https://github.com/rh-aiservices-bu/s4) for development, test, and demonstration. It is not intended for production S3 object storage. For production S3 workloads on OpenShift, use the Validated Patterns **[openshift-data-foundations](https://github.com/validatedpatterns/openshift-data-foundations-chart)** chart ([ODF](https://www.redhat.com/en/technologies/cloud-computing/openshift-data-foundation) on the VP catalog: `chart: openshift-data-foundations` from [charts.validatedpatterns.io](https://charts.validatedpatterns.io)).\n\nDefaults assume an OpenShift cluster: OpenShift Route for the Web UI (Ingress disabled), cluster-default StorageClass for PVCs, pinned S4 image tag, and restricted pod security contexts compatible with the `restricted-v2` SCC.\n\n## Bucket provisioning\n\nBucket create/destroy logic is shipped as an Ansible playbook in a ConfigMap (`playbooks/s4-buckets.yml`), mounted into the [utility-container](https://quay.io/validatedpatterns/utility-container) (ansible + `amazon.aws`). Default variables live in `vars/defaults.yml` on the mount (ConfigMap key `vars.defaults.yml`); the Job and CronJob pass `s4Role.buckets`, **`s4-credentials`**, and optional `s4Role.destroy` at runtime.\n\nThe playbook and variable model were adapted from [eduffy-redhat/s4-role](https://github.com/eduffy-redhat/s4-role). **Credit to Evan Duffy (Red Hat)** for the original Ansible role and approach to managing buckets on an S4 endpoint.\n\n## Secrets (Validated Patterns)\n\nS4 has two access paths, stored in **two Vault secrets** and merged into **one Kubernetes Secret** for the upstream `s4` subchart (no subchart changes):\n\n| Access path | Keys | Vault secret (example) |\n|-------------|------|------------------------|\n| **Web UI** | `UI_USERNAME`, `UI_PASSWORD` [, `JWT_SECRET`] | `s4-ui-credentials` |\n| **S3 API** | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` | `s4-api-credentials` |\n\nExternal Secrets Operator uses **one** `ExternalSecret` (`s4Credentials.secretName`) with two `dataFrom.extract` entries (UI and API Vault paths). That avoids `creationPolicy: Merge`, which fails if the target Secret does not exist yet when both resources reconcile in parallel. The resulting secret is passed to the unmodified `s4` subchart via `s4.s3.existingSecret` and is used by bucket Jobs. The API Vault path is the RGW identity for the endpoint, provisioning, and application consumers.\n\nDefault examples use `s4admin` for the UI user and S3 access key id; the UI password and API secret key are **generated** (`advancedPolicy`).\n\nCopy `examples/secrets/values-secret.v2.yaml` into your pattern `common/examples/secrets/` and run your pattern secrets tooling (e.g. `./scripts/make-secrets.sh`). Then point the chart at the Vault paths with a values overlay like `examples/chart-secret-values.yaml`.\n\n### `examples/secrets/values-secret.v2.yaml`\n\n```yaml\n# NEVER COMMIT REAL SECRETS TO GIT\n#\n# Validated Patterns secrets example for vp-s4-storage.\n# Use from your pattern repo with the secrets tooling, e.g.:\n#   ./scripts/make-secrets.sh -f common/examples/secrets/values-secret.v2.yaml\n#\n# Two Vault secrets (Web UI vs S3 API) merge into Kubernetes Secret s4-credentials.\n# Wire Vault paths into the chart via examples/chart-secret-values.yaml.\n\nversion: \"2.0\"\nbackingStore: vault\n\nvaultPolicies:\n  basicPolicy: |\n    length=10\n    rule \"charset\" { charset = \"abcdefghijklmnopqrstuvwxyz\" min-chars = 1 }\n    rule \"charset\" { charset = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" min-chars = 1 }\n    rule \"charset\" { charset = \"0123456789\" min-chars = 1 }\n\n  advancedPolicy: |\n    length=20\n    rule \"charset\" { charset = \"abcdefghijklmnopqrstuvwxyz\" min-chars = 1 }\n    rule \"charset\" { charset = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" min-chars = 1 }\n    rule \"charset\" { charset = \"0123456789\" min-chars = 1 }\n    rule \"charset\" { charset = \"!@#$%^\u0026*\" min-chars = 1 }\n\nsecrets:\n  - name: s4-ui-credentials\n    vaultPrefixes:\n      - global\n    fields:\n      - name: UI_USERNAME\n        value: s4admin\n        onMissingValue: error\n      - name: UI_PASSWORD\n        onMissingValue: generate\n        override: true\n        vaultPolicy: advancedPolicy\n\n  - name: s4-api-credentials\n    vaultPrefixes:\n      - global\n    fields:\n      - name: AWS_ACCESS_KEY_ID\n        value: s4admin\n        onMissingValue: error\n      - name: AWS_SECRET_ACCESS_KEY\n        onMissingValue: generate\n        override: true\n        vaultPolicy: advancedPolicy\n\n```\n\n### `examples/chart-secret-values.yaml`\n\n```yaml\n# Overlay for vp-s4-storage after running pattern secrets tooling.\n# Adjust vaultKey paths to match your hub/site prefix (global, cluster, etc.).\n#\n#   secret/data/global/s4-ui-credentials\n#   secret/data/global/s4-api-credentials\n\ns4UICredentials:\n  vaultKey: secret/data/global/s4-ui-credentials\n\ns4APICredentials:\n  vaultKey: secret/data/global/s4-api-credentials\n\n```\n\n## Validated Patterns clusterGroup\n\nWhen this chart is published to [charts.validatedpatterns.io](https://charts.validatedpatterns.io), add a namespace and Argo CD application under `clusterGroup` in your hub or site values (same style as other `vp-*` catalog charts):\n\n### `examples/clustergroup-application.yaml`\n\n```yaml\n# Example clusterGroup fragment for a Validated Patterns hub (or site) values file.\n# Assumes vp-s4-storage is published on https://charts.validatedpatterns.io\n# (same catalog as vp-rbac, aap-config, vp-stakater-reloader, etc.).\n#\n# Merge into values-global.yaml / values-hub.yaml under clusterGroup:.\n# Run secrets tooling first (see examples/secrets/values-secret.v2.yaml).\n\nclusterGroup:\n  namespaces:\n    - s4-storage\n\n  # argoProject must already be listed in clusterGroup.argoProjects\n  argoProjects:\n    - hub\n\n  applications:\n    vp-s4-storage:\n      name: vp-s4-storage\n      namespace: vp-s4-storage\n      argoProject: hub\n      chart: vp-s4-storage\n      chartVersion: 0.2.*\n      overrides:\n        # Vault paths from examples/secrets/values-secret.v2.yaml (adjust prefix as needed)\n        - name: s4UICredentials.vaultKey\n          value: secret/data/global/s4-ui-credentials\n        - name: s4APICredentials.vaultKey\n          value: secret/data/global/s4-api-credentials\n        # Bucket names for the imperative Job/CronJob playbook\n        - name: s4Role.buckets[0]\n          value: my-app-data\n        - name: s4Role.buckets[1]\n          value: my-app-logs\n        # vp-rbac Role/RoleBinding namespace must match the Argo CD app namespace\n        - name: vp-rbac.serviceAccounts.vp-s4-storage-sa.namespace\n          value: vp-s4-storage\n        - name: vp-rbac.roles.external-secrets-validator.namespace\n          value: vp-s4-storage\n        # ConsoleLink is enabled by default; href uses global.localClusterDomain from values-global.yaml\n        # from values-global.yaml (same as clustergroup Argo CD ConsoleLinks). Optional overrides:\n        # - name: consoleLink.href\n        #   value: https://s4.apps.mycluster.example.com\n        # - name: s4.route.host\n        #   value: s4.apps.mycluster.example.com\n        # Optional Route hostnames (both Routes enabled by default; see examples/clustergroup-route-overrides.yaml)\n        # - name: s4.route.host\n        #   value: s4.apps.mycluster.example.com\n        # - name: s4.route.s3Api.host\n        #   value: s3-s4.apps.mycluster.example.com\n\n```\n\nArgo CD pulls `chart: vp-s4-storage` and `chartVersion: 0.1.*` from the Validated Patterns Helm repo (no `repoURL` required unless you override the default catalog URL). Use `overrides` for Vault keys, bucket lists, and optional Route hostnames. Ensure the `argoProject` you reference is listed in `clusterGroup.argoProjects`.\n\n## Configuring OpenShift Routes\n\nRoutes are rendered by the upstream `s4` subchart (`charts/s4/templates/route.yaml` and `route-s3.yaml`). This wrapper passes settings under `s4.route.*` in Helm values or Argo CD `overrides`.\n\n### Helm values file\n\nFull examples (uncomment the scenario you need):\n\n```yaml\n# Helm values examples for OpenShift Routes (s4 subchart keys under s4.route.*)\n# Use with: helm install ... -f examples/route-values.yaml\n# Or merge selected keys into a pattern values overlay / clusterGroup overrides.\n\n# -----------------------------------------------------------------------------\n# 1) Default — Web UI + S3 API Routes, cluster-assigned FQDNs (chart defaults)\n# -----------------------------------------------------------------------------\n# s4:\n#   route:\n#     enabled: true\n#     host: \"\"\n#     annotations:\n#       haproxy.router.openshift.io/timeout: 600s\n#     s3Api:\n#       enabled: true\n#       host: \"\"\n#       annotations:\n#         haproxy.router.openshift.io/timeout: 600s\n#       tls:\n#         termination: edge\n#         insecureEdgeTerminationPolicy: Allow  # HTTP :80 and HTTPS :443\n\n# -----------------------------------------------------------------------------\n# 2) Web UI — custom FQDN (DNS must point at the cluster ingress/router)\n# -----------------------------------------------------------------------------\n# s4:\n#   route:\n#     enabled: true\n#     host: s4.apps.mycluster.example.com\n#     tls:\n#       termination: edge\n#       insecureEdgeTerminationPolicy: Redirect\n\n# -----------------------------------------------------------------------------\n# 3) Web UI + S3 API — custom FQDNs on both Routes\n# -----------------------------------------------------------------------------\n# s4:\n#   route:\n#     enabled: true\n#     host: s4.apps.mycluster.example.com\n#     s3Api:\n#       enabled: true\n#       host: s3-s4.apps.mycluster.example.com\n#       annotations:\n#         haproxy.router.openshift.io/timeout: 600s\n#       tls:\n#         termination: edge\n#         insecureEdgeTerminationPolicy: Allow  # or Redirect for HTTPS-only\n\n# -----------------------------------------------------------------------------\n# 4) S3 API internal only (Web UI Route still public)\n# -----------------------------------------------------------------------------\n# s4:\n#   route:\n#     enabled: true\n#     s3Api:\n#       enabled: false\n\n# -----------------------------------------------------------------------------\n# 5) Disable Routes (Ingress or in-cluster / port-forward only)\n# -----------------------------------------------------------------------------\n# s4:\n#   route:\n#     enabled: false\n#   ingress:\n#     enabled: true\n#     className: openshift-default\n#     hosts:\n#       - host: s4.apps.mycluster.example.com\n#         paths:\n#           - path: /\n#             pathType: Prefix\n\n```\n\n### clusterGroup overrides\n\nCopy override blocks into `clusterGroup.applications.vp-s4-storage.overrides`:\n\n```yaml\n# clusterGroup overrides only — merge into clusterGroup.applications.vp-s4-storage.overrides\n# Chart defaults enable both Web UI and S3 API Routes (cluster-assigned FQDNs).\n#\n# Argo CD override names use dotted Helm value paths. Escape dots in annotation keys\n# with a backslash in the override name.\n\n# --- Defaults: no overrides (both Routes enabled, auto hostname) ---\n\n# --- Web UI: pinned FQDN ---\noverrides_web_ui_host:\n  - name: s4.route.host\n    value: s4.apps.mycluster.example.com\n\n# --- S3 API: pinned FQDN ---\noverrides_s3_api_host:\n  - name: s4.route.s3Api.host\n    value: s3-s4.apps.mycluster.example.com\n\n# --- Web UI + S3 API: pinned FQDNs on both ---\noverrides_web_ui_and_s3_api_hosts:\n  - name: s4.route.host\n    value: s4.apps.mycluster.example.com\n  - name: s4.route.s3Api.host\n    value: s3-s4.apps.mycluster.example.com\n\n# --- Web UI: upload timeout annotation ---\noverrides_web_ui_annotation:\n  - name: s4.route.annotations.haproxy\\.router\\.openshift\\.io/timeout\n    value: 600s\n\n# --- S3 API Route off (in-cluster Service only; Web UI Route unchanged) ---\noverrides_s3_api_internal_only:\n  - name: s4.route.s3Api.enabled\n    value: \"false\"\n\n# --- All OpenShift Routes off ---\noverrides_disable_routes:\n  - name: s4.route.enabled\n    value: \"false\"\n\n```\n\nTypical override names:\n\n| Goal | Override |\n|------|----------|\n| Custom Web UI FQDN | `s4.route.host` |\n| Router annotation | `s4.route.annotations.haproxy\\.router\\.openshift\\.io/timeout` |\n| Custom S3 API FQDN | `s4.route.s3Api.host` |\n| Disable S3 API Route | `s4.route.s3Api.enabled: \"false\"` |\n| No Routes | `s4.route.enabled: \"false\"` |\n\nRendered resources use the release namespace (e.g. `s4-storage`). Two Routes are created by default: Web UI (`web-ui`, port 5000) and S3 API (`s3-api`, port 7480, object name suffix `-api`).\n\n## Routes and FQDNs (Web UI vs S3 consumers)\n\nOpenShift defaults expose both the **Web UI** and **S3 API** on separate edge-terminated Routes (`s4.route.enabled` and `s4.route.s3Api.enabled`, both `true`). Each gets its own FQDN unless you set `s4.route.host` or `s4.route.s3Api.host`.\n\n### Web UI (human / admin browser access)\n\n| Setting | Behavior |\n|---------|----------|\n| `s4.route.host` empty | OpenShift assigns a predictable hostname (see below). |\n| `s4.route.host` set | Route uses that FQDN; DNS must resolve to the cluster ingress/router. |\n| TLS | Edge termination (HTTPS at the router; HTTP to the pod). |\n\n### Predictable FQDNs when `host` is empty\n\nYes. If you do not set `s4.route.host` or `s4.route.s3Api.host`, OpenShift fills `spec.host` on each Route using the cluster ingress domain. The pattern is:\n\n```text\n\u003croute.metadata.name\u003e-\u003cnamespace\u003e.\u003cingress-domain\u003e\n```\n\n**Step 1 — Route object names (from Helm, before apply)**\n\nThe `s4` subchart names routes from `s4.fullname`:\n\n| Route | `metadata.name` |\n|-------|-----------------|\n| Web UI | `{s4.fullname}` |\n| S3 API | `{s4.fullname}-api` |\n\n`{s4.fullname}` is computed as:\n\n- `s4.fullnameOverride` if set, else\n- `Release.Name` if it **contains** the substring `s4`, else\n- `{Release.Name}-s4`\n\nFor a typical Validated Patterns app (`name: vp-s4-storage`, Argo CD release `vp-s4-storage`), `Release.Name` contains `s4`, so:\n\n| Resource | Name |\n|----------|------|\n| Web UI Route | `vp-s4-storage` |\n| S3 API Route | `vp-s4-storage-api` |\n| Service (in-cluster S3) | `vp-s4-storage` |\n\nIf your release name does not contain `s4` (e.g. release `storage`), use `storage-s4` and `storage-s4-api` instead.\n\n**Step 2 — Ingress domain (cluster constant)**\n\n```bash\noc get ingresses.config cluster -o jsonpath='{.status.domain}{\"\\n\"}'\n```\n\nExample output: `apps.ocp4.example.com` (varies per cluster; set by install or `Ingress.config.openshift.io`).\n\n**Step 3 — Assemble the FQDN**\n\nWith namespace `s4-storage` and ingress domain `apps.ocp4.example.com`:\n\n```text\nWeb UI:  vp-s4-storage-s4-storage.apps.ocp4.example.com\nS3 API:  vp-s4-storage-api-s4-storage.apps.ocp4.example.com\n```\n\nTemplate:\n\n```text\nhttps://{route-name}-{namespace}.{ingress-domain}    # Web UI or S3 Route (edge TLS)\nhttp://{s4.fullname}.{namespace}.svc:7480          # in-cluster S3 only\n```\n\nAfter deploy, confirm:\n\n```bash\nINGRESS_DOMAIN=$(oc get ingresses.config cluster -o jsonpath='{.status.domain}')\nNS=s4-storage\necho \"Web UI:  vp-s4-storage-${NS}.${INGRESS_DOMAIN}\"\necho \"S3 API:  vp-s4-storage-api-${NS}.${INGRESS_DOMAIN}\"\n\noc get route -n \"${NS}\" -l app.kubernetes.io/name=s4 -o custom-columns=NAME:.metadata.name,HOST:.spec.host\n```\n\nLog in to the Web UI with **`s4-credentials`** (`UI_USERNAME` / `UI_PASSWORD`). Do not use the Web UI Route URL as an S3 endpoint.\n\n### S3 / bucket access (applications and automation)\n\nUse the S3 keys in **`s4-credentials`** (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`), region `us-east-1`. The same secret backs the RGW process, bucket Jobs (`s4Role.buckets`), and application clients.\n\n**In-cluster** (typical for pods on the same cluster):\n\n```text\nhttp://vp-s4-storage.s4-storage.svc:7480\n```\n\n```bash\nexport AWS_ACCESS_KEY_ID=$(oc get secret s4-credentials -n s4-storage -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 -d)\nexport AWS_SECRET_ACCESS_KEY=$(oc get secret s4-credentials -n s4-storage -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 -d)\naws --endpoint-url http://vp-s4-storage.s4-storage.svc:7480 s3 ls\n```\n\n**Outside the cluster** (default chart also creates an S3 API Route):\n\nThe S3 API Route defaults to `s4.route.s3Api.tls.insecureEdgeTerminationPolicy: Allow`, so clients can use **HTTP on port 80** or **HTTPS on port 443** (edge termination). The Web UI Route still redirects HTTP to HTTPS (`Redirect`).\n\n```bash\nS3_HOST=$(oc get route vp-s4-storage-api -n s4-storage -o jsonpath='{.spec.host}')\naws --endpoint-url \"http://${S3_HOST}\" s3 ls\n# or: aws --endpoint-url \"https://${S3_HOST}\" s3 ls\n```\n\nOr set `s4.route.s3Api.host` to a stable name (e.g. `s3-s4.apps.mycluster.example.com`) in values or clusterGroup overrides. Set `s4.route.s3Api.tls.insecureEdgeTerminationPolicy: Redirect` to force HTTPS only. Restrict access with network policy; the S3 Route exposes the API outside the cluster.\n\n## Notable changes\n\n### Argo CD sync wave ordering\n\nDefault `s4.commonAnnotations` sets `argocd.argoproj.io/sync-wave: \"2\"` on S4 subchart resources (Deployment, Service, PVC, and related objects). Umbrella-chart resources keep their existing waves: ExternalSecrets and the validation Job at **1**, bucket ConfigMap at **2**, bootstrap Job at **3**, CronJob at **5**. That ensures credentials exist before the S4 Deployment starts and the bootstrap Job still runs after the workload is up.\n\n### S3 API Route HTTP (port 80)\n\nDefault `s4.route.s3Api.tls.insecureEdgeTerminationPolicy` is `Allow` so the S3 API Route serves HTTP on port 80 as well as HTTPS on port 443. The Web UI Route remains `Redirect` (HTTP to HTTPS).\n\n### OpenShift ConsoleLink (Web UI)\n\nWhen the Web UI Route is enabled (`consoleLink.enabled` defaults to `true`), the chart creates a cluster `ConsoleLink` in the console **Application menu** (`consoleLink.section: Storage`), matching the Validated Patterns clustergroup style used for Argo CD (`common/clustergroup/templates/plumbing/argocd.yaml`) and Vault ConsoleLinks. The `spec.href` URL is `s4.route.host` when set, else `https://{route}-{namespace}.{ingress-domain}` with `ingress-domain` from `coalesce(consoleLink.ingressDomain, global.localClusterDomain)` — `global.localClusterDomain` is set by the pattern framework in `values-global.yaml`. Override with `consoleLink.href` if needed. Set `consoleLink.enabled: false` to disable. The icon is the 64×64 PNG from [rh-aiservices-bu/s4](https://github.com/rh-aiservices-bu/s4) (`assets/s4-icon-64x64.png`), bundled in the chart as a data URI unless `consoleLink.imageURL` is set.\n\n**Homepage:** \u003chttps://github.com/rh-aiservices-bu/s4\u003e\n\n## Source Code\n\n* \u003chttps://github.com/rh-aiservices-bu/s4\u003e\n* \u003chttps://github.com/eduffy-redhat/s4-role\u003e\n\n## Requirements\n\n| Repository | Name | Version |\n|------------|------|---------|\n| file://charts/s4 | s4 | 0.1.0 |\n| https://charts.validatedpatterns.io | vp-rbac | 0.1.* |\n\n## Values\n\n| Key | Type | Default | Description |\n|-----|------|---------|-------------|\n| configJob.activeDeadlineSeconds | int | `3600` |  |\n| configJob.configTimeout | int | `1800` |  |\n| configJob.disabled | bool | `false` |  |\n| configJob.image | string | `\"quay.io/validatedpatterns/utility-container:latest\"` |  |\n| configJob.imagePullPolicy | string | `\"IfNotPresent\"` |  |\n| configJob.s4ReadyTimeoutSeconds | int | `600` |  |\n| configJob.schedule | string | `\"10 */2 * * *\"` |  |\n| consoleLink.enabled | bool | `true` |  |\n| consoleLink.href | string | `\"\"` |  |\n| consoleLink.imageURL | string | `\"\"` |  |\n| consoleLink.ingressDomain | string | `\"\"` |  |\n| consoleLink.section | string | `\"Storage\"` |  |\n| consoleLink.text | string | `\"S4 Web UI\"` |  |\n| s4.auth.cookieRequireHttps | bool | `true` |  |\n| s4.auth.enabled | bool | `true` |  |\n| s4.commonAnnotations.\"argocd.argoproj.io/sync-wave\" | string | `\"2\"` |  |\n| s4.image.pullPolicy | string | `\"IfNotPresent\"` |  |\n| s4.image.repository | string | `\"quay.io/rh-aiservices-bu/s4\"` |  |\n| s4.image.tag | string | `\"0.3.2\"` |  |\n| s4.ingress.enabled | bool | `false` |  |\n| s4.ingress.s3Api.enabled | bool | `false` |  |\n| s4.podSecurityContext.runAsNonRoot | bool | `true` |  |\n| s4.route.annotations.\"haproxy.router.openshift.io/timeout\" | string | `\"600s\"` |  |\n| s4.route.enabled | bool | `true` |  |\n| s4.route.s3Api.annotations.\"haproxy.router.openshift.io/timeout\" | string | `\"600s\"` |  |\n| s4.route.s3Api.enabled | bool | `true` |  |\n| s4.route.s3Api.tls.insecureEdgeTerminationPolicy | string | `\"Allow\"` |  |\n| s4.route.s3Api.tls.termination | string | `\"edge\"` |  |\n| s4.route.tls.insecureEdgeTerminationPolicy | string | `\"Redirect\"` |  |\n| s4.route.tls.termination | string | `\"edge\"` |  |\n| s4.s3.existingSecret | string | `\"s4-credentials\"` |  |\n| s4.securityContext.allowPrivilegeEscalation | bool | `false` |  |\n| s4.securityContext.capabilities.drop[0] | string | `\"ALL\"` |  |\n| s4.securityContext.runAsNonRoot | bool | `true` |  |\n| s4.securityContext.seccompProfile.type | string | `\"RuntimeDefault\"` |  |\n| s4.service.nodePort.enabled | bool | `false` |  |\n| s4.service.type | string | `\"ClusterIP\"` |  |\n| s4.serviceAccount.create | bool | `true` |  |\n| s4.storage.data.accessMode | string | `\"ReadWriteOnce\"` |  |\n| s4.storage.data.size | string | `\"10Gi\"` |  |\n| s4.storage.data.storageClass | string | `\"\"` |  |\n| s4.storage.localStorage.enabled | bool | `false` |  |\n| s4APICredentials.vaultKey | string | `\"secret/data/global/s4-api-credentials\"` |  |\n| s4Credentials.secretName | string | `\"s4-credentials\"` |  |\n| s4Role.buckets | list | `[]` |  |\n| s4Role.destroy | bool | `false` |  |\n| s4Role.endpoint.address | string | `\"\"` |  |\n| s4Role.endpoint.port | int | `7480` |  |\n| s4Role.endpoint.protocol | string | `\"http\"` |  |\n| s4UICredentials.vaultKey | string | `\"secret/data/global/s4-ui-credentials\"` |  |\n| secretStore.kind | string | `\"ClusterSecretStore\"` |  |\n| secretStore.name | string | `\"vault-backend\"` |  |\n| serviceAccountName | string | `\"vp-s4-storage-sa\"` |  |\n| serviceAccountNamespace | string | `\"\"` |  |\n| validationJob.activeDeadlineSeconds | int | `3600` |  |\n| validationJob.disabled | bool | `false` |  |\n| vp-rbac.roles.external-secrets-validator.namespace | string | `\"\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].apiGroups[0] | string | `\"external-secrets.io\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].apiGroups[1] | string | `\"\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].resources[0] | string | `\"externalsecrets\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].resources[1] | string | `\"secrets\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].verbs[0] | string | `\"get\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].verbs[1] | string | `\"list\"` |  |\n| vp-rbac.roles.external-secrets-validator.rules[0].verbs[2] | string | `\"watch\"` |  |\n| vp-rbac.serviceAccounts.vp-s4-storage-sa.namespace | string | `\"\"` |  |\n| vp-rbac.serviceAccounts.vp-s4-storage-sa.roleBindings.clusterRoles | list | `[]` |  |\n| vp-rbac.serviceAccounts.vp-s4-storage-sa.roleBindings.roles[0] | string | `\"external-secrets-validator\"` |  |\n\n----------------------------------------------\nAutogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalidatedpatterns%2Fvp-s4-storage-chart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalidatedpatterns%2Fvp-s4-storage-chart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalidatedpatterns%2Fvp-s4-storage-chart/lists"}