fix: consume protected platform values #63

Merged
eding merged 1 commit from feat/platform-delivery-values into main 2026-09-16 20:08:41 +02:00
3 changed files with 24 additions and 33 deletions

View file

@ -27,10 +27,6 @@ spec:
- name: environment - name: environment
- name: pr-number - name: pr-number
default: "" default: ""
- name: platform-url
default: ""
- name: platform-revision
default: ""
- name: forgejo-base-url - name: forgejo-base-url
default: "" default: ""
- name: forgejo-owner - name: forgejo-owner
@ -57,10 +53,6 @@ spec:
value: $(params.environment) value: $(params.environment)
- name: PR_NUMBER - name: PR_NUMBER
value: $(params.pr-number) value: $(params.pr-number)
- name: PLATFORM_URL
value: $(params.platform-url)
- name: PLATFORM_REVISION
value: $(params.platform-revision)
- name: FORGEJO_BASE_URL - name: FORGEJO_BASE_URL
value: $(params.forgejo-base-url) value: $(params.forgejo-base-url)
- name: FORGEJO_OWNER - name: FORGEJO_OWNER
@ -102,8 +94,6 @@ spec:
cd /tmp/manifests cd /tmp/manifests
if [ "$ENVIRONMENT" = preview ]; then if [ "$ENVIRONMENT" = preview ]; then
valid_pr_number "$PR_NUMBER" valid_pr_number "$PR_NUMBER"
valid_url "$PLATFORM_URL"
valid_revision "$PLATFORM_REVISION"
app_dir="apps/previews/$APP_NAME-pr-$PR_NUMBER" app_dir="apps/previews/$APP_NAME-pr-$PR_NUMBER"
marker="$app_dir/ownership.yaml" marker="$app_dir/ownership.yaml"
if [ -e "$app_dir" ]; then if [ -e "$app_dir" ]; then
@ -129,12 +119,7 @@ spec:
EOF EOF
cmp -s "$expected_marker" "$marker" || fail cmp -s "$expected_marker" "$marker" || fail
fi fi
git clone "$PLATFORM_URL" /tmp/platform
git -C /tmp/platform checkout "$PLATFORM_REVISION"
[ -f /tmp/platform/preview/values.yaml ] || fail
mkdir -p "$app_dir" mkdir -p "$app_dir"
cp /tmp/platform/preview/values.yaml "$app_dir/values.yaml"
sed -i "s/PLACEHOLDER_PR/$PR_NUMBER/g" "$app_dir/values.yaml"
cat > "$marker" <<EOF cat > "$marker" <<EOF
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
@ -169,14 +154,20 @@ spec:
chart: chart:
spec: spec:
chart: ./charts/$APP_NAME chart: ./charts/$APP_NAME
reconcileStrategy: Revision
sourceRef: sourceRef:
kind: GitRepository kind: GitRepository
name: $APP_NAME name: $APP_NAME
namespace: flux-system namespace: flux-system
valuesFiles:
- ./charts/$APP_NAME/values.yaml
- ./preview/values.yaml
values: values:
image: image:
repository: $IMAGE repository: $IMAGE
tag: $TAG tag: $TAG
gateway:
hostname: $APP_NAME-pr-$PR_NUMBER.{{ .ClusterDomain }}
EOF EOF
cat > "$app_dir/kustomization.yaml" <<EOF cat > "$app_dir/kustomization.yaml" <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
@ -212,10 +203,14 @@ spec:
chart: chart:
spec: spec:
chart: ./charts/$APP_NAME chart: ./charts/$APP_NAME
reconcileStrategy: Revision
sourceRef: sourceRef:
kind: GitRepository kind: GitRepository
name: $APP_NAME name: $APP_NAME
namespace: flux-system namespace: flux-system
valuesFiles:
- ./charts/$APP_NAME/values.yaml
- ./staging/values.yaml
values: values:
image: image:
repository: $IMAGE repository: $IMAGE
@ -259,10 +254,14 @@ spec:
chart: chart:
spec: spec:
chart: ./charts/$APP_NAME chart: ./charts/$APP_NAME
reconcileStrategy: Revision
sourceRef: sourceRef:
kind: GitRepository kind: GitRepository
name: $APP_NAME name: $APP_NAME
namespace: flux-system namespace: flux-system
valuesFiles:
- ./charts/$APP_NAME/values.yaml
- ./production/values.yaml
values: values:
image: image:
repository: $IMAGE repository: $IMAGE
@ -628,10 +627,6 @@ spec:
default: {{ quote .ForgejoOwner }} default: {{ quote .ForgejoOwner }}
- name: manifests-repo - name: manifests-repo
default: {{ quote .ManifestsRepo }} default: {{ quote .ManifestsRepo }}
- name: platform-url
default: {{ quote .AppRepoURL }}
- name: platform-revision
default: {{ quote .PlatformBranch }}
tasks: tasks:
- name: build-layer - name: build-layer
when: when:
@ -681,10 +676,6 @@ spec:
value: preview value: preview
- name: pr-number - name: pr-number
value: $(params.pr-number) value: $(params.pr-number)
- name: platform-url
value: $(params.platform-url)
- name: platform-revision
value: $(params.platform-revision)
- name: update-staging - name: update-staging
runAfter: [build-layer] runAfter: [build-layer]
when: when:

View file

@ -622,7 +622,6 @@ type appDeliveryTemplateConfig struct {
AppRepository string AppRepository string
AppRepoURL string AppRepoURL string
AppRepoRef string AppRepoRef string
PlatformBranch string
ProductionBranch string ProductionBranch string
ImageRepository string ImageRepository string
BuildStrategy string BuildStrategy string
@ -633,6 +632,7 @@ type appDeliveryTemplateConfig struct {
ManifestsURL string ManifestsURL string
ManifestsRepo string ManifestsRepo string
ManifestsBranch string ManifestsBranch string
ClusterDomain string
} }
var deliveryAppName = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,45}[a-z0-9])?$`) var deliveryAppName = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,45}[a-z0-9])?$`)
@ -654,11 +654,11 @@ func renderAppDelivery(cfg config.Config) ([]byte, error) {
} }
values := appDeliveryTemplateConfig{ values := appDeliveryTemplateConfig{
AppName: cfg.Delivery.AppName, AppRepository: appRepository, AppRepoURL: cfg.Delivery.AppRepoURL, AppName: cfg.Delivery.AppName, AppRepository: appRepository, AppRepoURL: cfg.Delivery.AppRepoURL,
AppRepoRef: cfg.Delivery.AppRepoRef, PlatformBranch: "maidn/platform-" + cfg.Delivery.AppName, ProductionBranch: cfg.Delivery.ProductionBranch, ImageRepository: cfg.Delivery.ImageRepository, AppRepoRef: cfg.Delivery.AppRepoRef, ProductionBranch: cfg.Delivery.ProductionBranch, ImageRepository: cfg.Delivery.ImageRepository,
BuildStrategy: cfg.Delivery.BuildStrategy, BuildOutputDirectory: cfg.Delivery.BuildOutputDirectory, BuildConfiguration: cfg.Delivery.BuildConfiguration, BuildStrategy: cfg.Delivery.BuildStrategy, BuildOutputDirectory: cfg.Delivery.BuildOutputDirectory, BuildConfiguration: cfg.Delivery.BuildConfiguration,
ForgejoBaseURL: origin, ForgejoOwner: cfg.Git.Owner, ManifestsURL: forgejo.CloneURL(origin, cfg.Git.Owner, cfg.Flux.ManifestsRepo), ManifestsRepo: cfg.Flux.ManifestsRepo, ManifestsBranch: cfg.Flux.Branch, ForgejoBaseURL: origin, ForgejoOwner: cfg.Git.Owner, ManifestsURL: forgejo.CloneURL(origin, cfg.Git.Owner, cfg.Flux.ManifestsRepo), ManifestsRepo: cfg.Flux.ManifestsRepo, ManifestsBranch: cfg.Flux.Branch, ClusterDomain: cfg.Flux.ClusterDomain,
} }
for name, value := range map[string]string{"appRepository": values.AppRepository, "appRepoUrl": values.AppRepoURL, "appRepoRef": values.AppRepoRef, "platformBranch": values.PlatformBranch, "productionBranch": values.ProductionBranch, "imageRepository": values.ImageRepository, "buildOutputDirectory": values.BuildOutputDirectory, "buildConfiguration": values.BuildConfiguration, "forgejoBaseUrl": values.ForgejoBaseURL, "forgejoOwner": values.ForgejoOwner, "manifestsUrl": values.ManifestsURL, "manifestsRepo": values.ManifestsRepo, "manifestsBranch": values.ManifestsBranch} { for name, value := range map[string]string{"appRepository": values.AppRepository, "appRepoUrl": values.AppRepoURL, "appRepoRef": values.AppRepoRef, "productionBranch": values.ProductionBranch, "imageRepository": values.ImageRepository, "buildOutputDirectory": values.BuildOutputDirectory, "buildConfiguration": values.BuildConfiguration, "forgejoBaseUrl": values.ForgejoBaseURL, "forgejoOwner": values.ForgejoOwner, "manifestsUrl": values.ManifestsURL, "manifestsRepo": values.ManifestsRepo, "manifestsBranch": values.ManifestsBranch, "clusterDomain": values.ClusterDomain} {
if value == "" || strings.ContainsAny(value, "\r\n") || config.RedactURL(value) != value { if value == "" || strings.ContainsAny(value, "\r\n") || config.RedactURL(value) != value {
return nil, fmt.Errorf("delivery %s cannot be empty or contain credentials", name) return nil, fmt.Errorf("delivery %s cannot be empty or contain credentials", name)
} }

View file

@ -111,7 +111,7 @@ func TestRemoveDuplicateAppDeliverySource(t *testing.T) {
func TestGeneratedDeliveryUsesCombinedStaticBuildArtifactContract(t *testing.T) { func TestGeneratedDeliveryUsesCombinedStaticBuildArtifactContract(t *testing.T) {
cfg := config.Config{ cfg := config.Config{
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"}, Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"}, Flux: config.FluxConfig{Branch: "main", ClusterDomain: "example.test", ManifestsRepo: "manifests"},
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"}, Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"},
} }
content, err := renderAppDelivery(cfg) content, err := renderAppDelivery(cfg)
@ -123,12 +123,12 @@ func TestGeneratedDeliveryUsesCombinedStaticBuildArtifactContract(t *testing.T)
t.Fatalf("generated delivery does not contain %q", expected) t.Fatalf("generated delivery does not contain %q", expected)
} }
} }
for _, expected := range []string{"name: platform-url\n default: \"https://git.example.test/apps/web-ui.git\"", "name: platform-revision\n default: \"maidn/platform-web-ui\"", "git clone \"$PLATFORM_URL\" /tmp/platform", "/tmp/platform/preview/values.yaml"} { for _, expected := range []string{"reconcileStrategy: Revision", "valuesFiles:\n - ./charts/$APP_NAME/values.yaml\n - ./preview/values.yaml", "valuesFiles:\n - ./charts/$APP_NAME/values.yaml\n - ./staging/values.yaml", "valuesFiles:\n - ./charts/$APP_NAME/values.yaml\n - ./production/values.yaml", "hostname: $APP_NAME-pr-$PR_NUMBER.example.test"} {
if !strings.Contains(string(content), expected) { if !strings.Contains(string(content), expected) {
t.Fatalf("generated delivery does not contain protected platform input %q", expected) t.Fatalf("generated delivery does not contain protected platform values %q", expected)
} }
} }
for _, unexpected := range []string{"maidn-git-clone", "maidn-node-static-build", "maidn-node-static-push", "runAfter: [clone]", "name: source", "workspace: source", "workspace: artifact", "easycsr", "test-org", "git rm -r", "$APP_URL", "$APP_REVISION", "/tmp/app/preview/values.yaml"} { for _, unexpected := range []string{"maidn-git-clone", "maidn-node-static-build", "maidn-node-static-push", "runAfter: [clone]", "name: source", "workspace: source", "workspace: artifact", "easycsr", "test-org", "git rm -r", "$APP_URL", "$APP_REVISION", "platform-url", "platform-revision", "/tmp/platform", "/tmp/app/preview/values.yaml"} {
if strings.Contains(string(content), unexpected) { if strings.Contains(string(content), unexpected) {
t.Fatalf("generated delivery contains unexpected %q", unexpected) t.Fatalf("generated delivery contains unexpected %q", unexpected)
} }
@ -138,7 +138,7 @@ func TestGeneratedDeliveryUsesCombinedStaticBuildArtifactContract(t *testing.T)
func TestGeneratedDeliveryUsesRuntimeImageWithoutStaticParameters(t *testing.T) { func TestGeneratedDeliveryUsesRuntimeImageWithoutStaticParameters(t *testing.T) {
cfg := config.Config{ cfg := config.Config{
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"}, Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"}, Flux: config.FluxConfig{Branch: "main", ClusterDomain: "example.test", ManifestsRepo: "manifests"},
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "runtime", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"}, Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "runtime", BuildOutputDirectory: "dist/web-ui", BuildConfiguration: "production"},
} }
content, err := renderAppDelivery(cfg) content, err := renderAppDelivery(cfg)
@ -160,7 +160,7 @@ func TestGeneratedDeliveryUsesRuntimeImageWithoutStaticParameters(t *testing.T)
func TestGeneratedDeliveryInitializesStagingAndPromotesByPullRequest(t *testing.T) { func TestGeneratedDeliveryInitializesStagingAndPromotesByPullRequest(t *testing.T) {
cfg := config.Config{ cfg := config.Config{
Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"}, Git: config.GitConfig{BaseURL: "https://git.example.test", Owner: "platform"},
Flux: config.FluxConfig{Branch: "main", ManifestsRepo: "manifests"}, Flux: config.FluxConfig{Branch: "main", ClusterDomain: "example.test", ManifestsRepo: "manifests"},
Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist", BuildConfiguration: "production"}, Delivery: config.DeliveryConfig{AppName: "web-ui", AppRepoURL: "https://git.example.test/apps/web-ui.git", AppRepoRef: "main", ProductionBranch: "production", ImageRepository: "registry.example.test/apps/web-ui", BuildStrategy: "static", BuildOutputDirectory: "dist", BuildConfiguration: "production"},
} }
content, err := renderAppDelivery(cfg) content, err := renderAppDelivery(cfg)