Skip to content

test(ci): seed branch to hunt and fix E2E flakes on main - #2919

Closed
IvanHunters wants to merge 14 commits into
mainfrom
test/ci-e2e-flake-hunt
Closed

IvanHunters wants to merge 14 commits into
mainfrom
test/ci-e2e-flake-hunt

Conversation

@IvanHunters

@IvanHunters IvanHunters commented Jun 15, 2026 •

Copy link
Copy Markdown
Collaborator

What this PR does

Seed commit that triggers the full Pull Request workflow on a clean main,
so we can iterate on real E2E flakes here without mixing them with any
in-flight feature changes. The first commit adds two trailing blank lines
to hack/cozytest.sh — a no-op, only there to make the paths filter pick
the change up (anything outside docs/** is enough).

Context: since 2026-06-10T11:00Z, no non-docs PR on main has produced
a green E2E run. The dominant symptoms across recent failures are:

  • Install Cozystack into sandbox step times out at 15:50, with a wide
    fan of HelmReleases never reaching Ready (kafka-operator, kamaji,
    kubeovn, kubevirt, linstor, cert-manager, ...).
  • bucketclaim/bucket-cozy-backups fails with
    bucketclasses.objectstorage.k8s.io "tenant-root" not found — race
    between BucketClass creation and the BucketClaim that references it.
  • strimzi-cluster-operator (kafka-operator) crashloops on a liveness
    probe to :8080, blocking kafka-rd.
  • The bats test Create and Verify Seeweedfs Bucket consistently times
    out on kubectl wait hr bucket-test --timeout=100s --for=condition=ready.

Subsequent commits on this branch will be targeted fixes for whichever of
these (or others) reproduce on the first run, one fix per commit so they
can be cherry-picked or reviewed individually.

Screenshots

N/A — no UI changes.

Release note

```release-note
NONE
```

Summary by CodeRabbit

  • Bug Fixes
    • Prevented Kubernetes admission/VAP crashes during OpenAPI schema publication by sanitizing boolean-form additionalProperties, and ensured open .spec schemas are published when needed.
    • Improved SeaweedFS Helm output for S3 TLS CLI arguments and corrected COSI serviceAccountName; also adjusted the generated S3 Service naming.
  • New Features
    • Added SeaweedFS COSI lock bucket class and readonly bucket access configuration.
  • Tests
    • Added Helm and OpenAPI regression tests covering TLS argument behavior, service account naming, and schema publication safety.
  • Chores
    • Expanded report output with “source-watcher diagnostics” collection.

No-op trailing newline in hack/cozytest.sh to trigger the full Pull
Request workflow on a clean main, so subsequent commits on this branch
can iterate on real E2E flakes.

Signed-off-by: Ivan Okhotnikov <[email protected]>
@coderabbitai

coderabbitai Bot commented Jun 15, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Three independent functional areas are enhanced: (1) Shell script diagnostics with source-watcher collection and trailing whitespace, (2) SeaweedFS Helm chart fixes for S3 TLS args decoupled from httpsPort, COSI provisioner service account naming, S3 service template updates applied via patches and tested, plus bucket class enhancements with object-lock and access policies, (3) OpenAPI schema sanitization to neutralize boolean-form additionalProperties that crash Kubernetes validation admission, with comprehensive test coverage.

Changes

Hack directory updates

Layer / File(s) Summary
Trailing blank lines in cozytest.sh
hack/cozytest.sh
Two empty lines appended at the end of the script; no functional code changes.
Source-watcher diagnostics collection
hack/cozyreport.sh
New collection block captures artifactgenerator and ocirepository state (text and YAML), source-watcher pod logs with previous logs, and cozy-fluxcd namespace Flux events before the cozystack apps collection phase.

SeaweedFS Helm chart fixes and enhancements

Layer / File(s) Summary
S3 TLS main port, COSI provisioner SA name, and service naming fixes
packages/system/seaweedfs/patches/s3-tls-main-port.patch, packages/system/seaweedfs/patches/cosi-provisioner-sa-name.patch, packages/system/seaweedfs/Makefile, packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml, packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml, packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml
Two Helm patches modify S3 deployment to render TLS args when enableSecurity is true regardless of httpsPort setting, and change COSI provisioner serviceAccountName to use global.seaweedfs.serviceAccountName with -objectstorage-provisioner suffix. Makefile applies both patches during chart preparation. S3 service template name updated to use seaweedfs.name helper with -s3 suffix instead of seaweedfs.componentName.
Helm chart test suite for S3 TLS and COSI SA
packages/system/seaweedfs/tests/s3_tls_cosi_sa_test.yaml
Test suite validates S3 TLS cert/key args are rendered when enableSecurity is true independent of httpsPort value, confirms httpsPort conditional still works when explicitly set, and verifies COSI provisioner uses global service account name with proper suffix.
COSI bucket class and access policies
packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-bucket-class.yaml
Helm template extended with BucketClass for object-lock-enabled lock bucket class with Retain deletion policy, and BucketAccessClass resources defining explicit readwrite and new readonly access policies.

OpenAPI schema sanitization for Kubernetes validation

Layer / File(s) Summary
Boolean additionalProperties sanitization helpers and patchSpec logic
pkg/cmd/server/openapi.go
New helpers markOpenObject and sanitizeBooleanAdditionalProperties recursively rewrite/remove boolean-form additionalProperties across nested schemas. patchSpec updated to publish open .spec schemas when JSON is empty and sanitize custom schemas before publishing, while preserving historical behavior. Extensions initialization in sanitizeForV2 changed to spec.Extensions{}.
Comprehensive test suite for schema sanitization
pkg/cmd/server/openapi_test.go
Tests verify x-kubernetes-preserve-unknown-fields extension is added and boolean additionalProperties removed for schemaless paths; object-form additionalProperties preserved; patched schemas process through celopenapi.SchemaDeclType without returning nil; and recursive sanitization across all schema depths (properties, items, combinators) produces no boolean nodes and safe VAP type-checking.

Sequence Diagram

sequenceDiagram
  participant Developer
  participant UserSchema as User-supplied OpenAPI Schema
  participant patchSpec
  participant Sanitize as sanitizeBooleanAdditionalProperties
  participant markOpen as markOpenObject
  participant KubeValidator as Kubernetes Validator
  
  Developer->>UserSchema: Submit schema with boolean additionalProperties
  UserSchema->>patchSpec: Parse user schema
  patchSpec->>Sanitize: Detect and rewrite boolean additionalProperties
  Sanitize->>markOpen: Mark as open with x-kubernetes-preserve-unknown-fields
  markOpen->>patchSpec: Return sanitized schema
  patchSpec->>KubeValidator: Publish safe schema to admission controller
  KubeValidator->>KubeValidator: SchemaDeclType succeeds without nil return
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~40 minutes

Possibly related PRs

  • cozystack/cozystack#2834: Both PRs modify the SeaweedFS Helm chart templates around the same areas—COSI objectstorage-provisioner serviceAccountName wiring and S3 TLS/tlsArgs rendering—so the main PR's SeaweedFS-specific template/patch updates are directly connected to the chart/vendor bump changes.

Suggested labels

area/storage, kind/bug, size/M

Suggested reviewers

  • myasnikovdaniil
  • lllamnyp
  • androndo
  • sircthulhu
  • kvaps

Poem

🐇 SeaweedFS TLS hops free from httpsPort's gate,
COSI provisioners dance with global grace,
Bucket locks hold fast, access policies in place,
While schemas shed their boolean bait,
Kubernetes validation no longer meets cruel fate! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title describes seeding a branch to investigate E2E test flakes, but the actual changeset includes multiple substantive fixes to SeaweedFS configuration, S3 service naming, COSI provisioner setup, and OpenAPI schema sanitization—significantly beyond the stated test-seeding objective. Revise the title to accurately reflect the main changes: e.g., 'fix: restore seaweedfs S3 service name and add TLS/COSI provisioner patches' or break into separate focused commits with corresponding titles.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/ci-e2e-flake-hunt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size/XS This PR changes 0-9 lines, ignoring generated files area/ci Issues or PRs related to CI workflows, GitHub Actions, automation labels Jun 15, 2026
@IvanHunters
IvanHunters marked this pull request as ready for review June 15, 2026 09:09
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a minimal, no-op change to the CI script to force a fresh execution of the full test suite. The primary objective is to create a controlled environment for identifying and resolving recurring E2E test failures that have been impacting the stability of the main branch.

Highlights

  • CI/CD Debugging: Added a seed commit to trigger the full Pull Request workflow on the main branch to isolate and investigate persistent E2E test flakes.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@dosubot dosubot Bot added area/testing Issues or PRs related to testing (e2e, bats, unit tests) debug Debugging in progress do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress kind/failing-test Categorizes issue or PR as related to a consistently or frequently failing test lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor labels Jun 15, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces minor formatting changes by adding trailing empty lines to the end of the hack/cozytest.sh script. There are no review comments, and I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Last run exposed 7 PackageSources stuck with Ready=Unknown reason=Progressing
for 30 minutes (openbao-application, qdrant-application, vpn-application,
vpa, linstor, virtualprivatecloud-application, capi-provider-bootstrap-kubeadm).
PackageSourceReconciler copies its Ready condition straight from the owned
ArtifactGenerator, so the real culprit lives in source-watcher — but the
current cozyreport bundle does not include any source-watcher artifacts,
so we cannot tell whether the OCIRepository fetch is the bottleneck, the
ArtifactGenerator queue is starved, or something else entirely.

Add a dedicated source-watcher section to hack/cozyreport.sh that captures:
- all ArtifactGenerators (list + full YAML)
- all OCIRepositories (list + full YAML)
- source-watcher pod listing and full logs (current and previous)
- events in cozy-fluxcd namespace

Signed-off-by: Ivan Okhotnikov <[email protected]>
@github-actions github-actions Bot added size/S This PR changes 10-29 lines, ignoring generated files and removed size/XS This PR changes 0-9 lines, ignoring generated files labels Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@hack/cozyreport.sh`:
- Around line 138-151: Harden the shell script by quoting all dynamic variable
expansions and using read with the -r flag. In the block starting with
DIR=$REPORT_DIR/kubernetes/source-watcher through the pod log loop, wrap all
variable expansions in double quotes (e.g., change $DIR to "$DIR" and $POD to
"$POD") to prevent word splitting and globbing issues. Additionally, change the
read command in the while loop from `while read POD` to `while read -r POD` to
prevent backslash interpretation and properly handle raw input from the kubectl
pipe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d283d3f3-8335-45c7-b20a-5c663fec1e64

📥 Commits

Reviewing files that changed from the base of the PR and between d1ee154 and 0794c85.

📒 Files selected for processing (1)
  • hack/cozyreport.sh

Comment thread hack/cozyreport.sh
Comment on lines +138 to +151
DIR=$REPORT_DIR/kubernetes/source-watcher
mkdir -p $DIR
# PackageSource copies its Ready condition straight from ArtifactGenerator.Status,
# so a stuck PackageSource ultimately means a stuck ArtifactGenerator or its OCIRepository source.
kubectl get artifactgenerators -A > $DIR/artifactgenerators.txt 2>&1 || true
kubectl get artifactgenerators -A -o yaml > $DIR/artifactgenerators.yaml 2>&1 || true
kubectl get ocirepositories -A > $DIR/ocirepositories.txt 2>&1 || true
kubectl get ocirepositories -A -o yaml > $DIR/ocirepositories.yaml 2>&1 || true
kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o wide > $DIR/pods.txt 2>&1 || true
kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o name 2>/dev/null | \
while read POD; do
POD=${POD#pod/}
kubectl logs -n cozy-fluxcd $POD --all-containers --prefix --tail=2000 > $DIR/$POD.log 2>&1 || true
kubectl logs -n cozy-fluxcd $POD --all-containers --prefix --tail=2000 --previous > $DIR/$POD-previous.log 2>&1 || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Quote dynamic shell variables and use read -r in the pod log loop.

Line 138 through Line 151 use unquoted expansions ($DIR, $POD) and read without -r, which can cause brittle behavior in shell parsing. Please harden this block.

Proposed patch
-DIR=$REPORT_DIR/kubernetes/source-watcher
-mkdir -p $DIR
+DIR="$REPORT_DIR/kubernetes/source-watcher"
+mkdir -p "$DIR"
@@
-kubectl get artifactgenerators -A > $DIR/artifactgenerators.txt 2>&1 || true
-kubectl get artifactgenerators -A -o yaml > $DIR/artifactgenerators.yaml 2>&1 || true
-kubectl get ocirepositories -A > $DIR/ocirepositories.txt 2>&1 || true
-kubectl get ocirepositories -A -o yaml > $DIR/ocirepositories.yaml 2>&1 || true
-kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o wide > $DIR/pods.txt 2>&1 || true
+kubectl get artifactgenerators -A > "$DIR/artifactgenerators.txt" 2>&1 || true
+kubectl get artifactgenerators -A -o yaml > "$DIR/artifactgenerators.yaml" 2>&1 || true
+kubectl get ocirepositories -A > "$DIR/ocirepositories.txt" 2>&1 || true
+kubectl get ocirepositories -A -o yaml > "$DIR/ocirepositories.yaml" 2>&1 || true
+kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o wide > "$DIR/pods.txt" 2>&1 || true
 kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o name 2>/dev/null | \
-  while read POD; do
+  while IFS= read -r POD; do
     POD=${POD#pod/}
-    kubectl logs -n cozy-fluxcd $POD --all-containers --prefix --tail=2000 > $DIR/$POD.log 2>&1 || true
-    kubectl logs -n cozy-fluxcd $POD --all-containers --prefix --tail=2000 --previous > $DIR/$POD-previous.log 2>&1 || true
+    kubectl logs -n cozy-fluxcd "$POD" --all-containers --prefix --tail=2000 > "$DIR/$POD.log" 2>&1 || true
+    kubectl logs -n cozy-fluxcd "$POD" --all-containers --prefix --tail=2000 --previous > "$DIR/$POD-previous.log" 2>&1 || true
   done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DIR=$REPORT_DIR/kubernetes/source-watcher
mkdir -p $DIR
# PackageSource copies its Ready condition straight from ArtifactGenerator.Status,
# so a stuck PackageSource ultimately means a stuck ArtifactGenerator or its OCIRepository source.
kubectl get artifactgenerators -A > $DIR/artifactgenerators.txt 2>&1 || true
kubectl get artifactgenerators -A -o yaml > $DIR/artifactgenerators.yaml 2>&1 || true
kubectl get ocirepositories -A > $DIR/ocirepositories.txt 2>&1 || true
kubectl get ocirepositories -A -o yaml > $DIR/ocirepositories.yaml 2>&1 || true
kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o wide > $DIR/pods.txt 2>&1 || true
kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o name 2>/dev/null | \
while read POD; do
POD=${POD#pod/}
kubectl logs -n cozy-fluxcd $POD --all-containers --prefix --tail=2000 > $DIR/$POD.log 2>&1 || true
kubectl logs -n cozy-fluxcd $POD --all-containers --prefix --tail=2000 --previous > $DIR/$POD-previous.log 2>&1 || true
DIR="$REPORT_DIR/kubernetes/source-watcher"
mkdir -p "$DIR"
# PackageSource copies its Ready condition straight from ArtifactGenerator.Status,
# so a stuck PackageSource ultimately means a stuck ArtifactGenerator or its OCIRepository source.
kubectl get artifactgenerators -A > "$DIR/artifactgenerators.txt" 2>&1 || true
kubectl get artifactgenerators -A -o yaml > "$DIR/artifactgenerators.yaml" 2>&1 || true
kubectl get ocirepositories -A > "$DIR/ocirepositories.txt" 2>&1 || true
kubectl get ocirepositories -A -o yaml > "$DIR/ocirepositories.yaml" 2>&1 || true
kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o wide > "$DIR/pods.txt" 2>&1 || true
kubectl get pods -n cozy-fluxcd -l app.kubernetes.io/name=source-watcher -o name 2>/dev/null | \
while IFS= read -r POD; do
POD=${POD#pod/}
kubectl logs -n cozy-fluxcd "$POD" --all-containers --prefix --tail=2000 > "$DIR/$POD.log" 2>&1 || true
kubectl logs -n cozy-fluxcd "$POD" --all-containers --prefix --tail=2000 --previous > "$DIR/$POD-previous.log" 2>&1 || true
done
🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 139-139: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 142-142: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 143-143: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 144-144: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 145-145: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 146-146: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 148-148: read without -r will mangle backslashes.

(SC2162)


[info] 150-150: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 150-150: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 150-150: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 151-151: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 151-151: Double quote to prevent globbing and word splitting.

(SC2086)


[info] 151-151: Double quote to prevent globbing and word splitting.

(SC2086)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hack/cozyreport.sh` around lines 138 - 151, Harden the shell script by
quoting all dynamic variable expansions and using read with the -r flag. In the
block starting with DIR=$REPORT_DIR/kubernetes/source-watcher through the pod
log loop, wrap all variable expansions in double quotes (e.g., change $DIR to
"$DIR" and $POD to "$POD") to prevent word splitting and globbing issues.
Additionally, change the read command in the while loop from `while read POD` to
`while read -r POD` to prevent backslash interpretation and properly handle raw
input from the kubectl pipe.

Source: Linters/SAST tools

myasnikovdaniil and others added 5 commits June 15, 2026 14:18
…not additionalProperties:true

cozystack-api published the free-form ".spec" of aggregated apps.cozystack.io
resources (Tenant, Application, ...) as the boolean `additionalProperties: true`.
The Kubernetes ValidatingAdmissionPolicy status type-checker run by
kube-controller-manager nil-dereferences when it recurses into that node, so as
soon as a VAP matches one of these resources (cozystack-tenant-host-policy on
tenants) KCM CrashLoopBackOffs cluster-wide and stalls reconciliation, failing
cold installs once the 3x install retry was removed.

Emit `x-kubernetes-preserve-unknown-fields: true` instead. It is semantically
equivalent ("arbitrary fields allowed") and the type-checker handles it safely.
All app custom schemas already use the safe object-form additionalProperties,
so patchSpec was the only source of the boolean form.

Adds a regression test that reproduces the exact crash through
k8s.io/apiserver/pkg/cel/openapi.SchemaDeclType (the entry point KCM uses): it
panics on the pre-fix code and passes after the fix.

Fixes #2863

Assisted-By: Claude <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
Signed-off-by: Ivan Okhotnikov <[email protected]>
…hed spec

Addresses review feedback on #2863. The previous fix only converted the open
spec wrapper cozystack-api injects, so a user-supplied ApplicationDefinition
openAPISchema carrying a boolean additionalProperties — declared explicitly at
the top level, or nested under properties/items/allOf/anyOf/oneOf — was
republished verbatim and re-triggered the kube-controller-manager VAP
type-checker crash. openAPISchema is untrusted input (external-apps and
operator-authored definitions flow through unvalidated), so close the whole
class rather than only the schemas cozystack ships.

Recursively rewrite every boolean-form additionalProperties (nil inner schema):
additionalProperties:true becomes x-kubernetes-preserve-unknown-fields:true,
additionalProperties:false is dropped. Both JSON forms carry a nil inner schema
and crash the type-checker identically; object-form maps are recursed into and
left intact. Also publish the schemaless spec from a fresh schema so no
inherited $ref or properties leak into the open object.

Regression tests cover top-level true/false and nested (properties, items,
allOf) boolean forms, asserting the published schema carries no boolean
additionalProperties node and does not panic SchemaDeclType.

Assisted-By: Claude <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
Signed-off-by: Ivan Okhotnikov <[email protected]>
…n sanitizer regression

Address review feedback from lexfrei and coderabbitai on
pkg/cmd/server/openapi_test.go:
TestPatchSpecSanitizesUserSuppliedBooleanAdditionalProperties only exercised the
top-level, properties, items, and allOf positions, leaving the one remaining
type-checker-reachable sanitizer branch untested: a boolean additionalProperties
nested inside an object-form additionalProperties. Deleting that recursion line
kept the whole suite green while the input panicked SchemaDeclType again (#2863).

Add the nested-under-additionalproperties case (the reachable blocker, verified
red->green by mutation) plus anyOf/oneOf/not cases (defense-in-depth: those
branches are recursed by the sanitizer but never traversed by SchemaDeclType, so
the hasBooleanAdditionalProperties assertion guards them). Rewrite the test
docstring to distinguish the type-checker-reachable cases from the
defense-in-depth ones, replacing the inaccurate "each case panics SchemaDeclType"
note.

Assisted-By: Claude <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
Signed-off-by: Ivan Okhotnikov <[email protected]>
Address review feedback from gemini-code-assist on pkg/cmd/server/openapi.go:
markOpenObject and sanitizeForV2 initialized s.Extensions with the generic
map[string]any{}; use the named spec.Extensions{} type instead, matching the
kube-openapi types and the generated definitions in zz_generated.openapi.go.
No behavioral change — spec.Extensions is defined as map[string]interface{}.

Assisted-By: Claude <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
Signed-off-by: Ivan Okhotnikov <[email protected]>
The 4.31 chart bump (#2834) broke E2E for every PR: tenant-root
seaweedfs-system never becomes ready.

1. S3 served plaintext. Until 4.05 the -cert.file/-key.file args were
   rendered whenever enableSecurity was set, so weed s3 served TLS on the
   main port (8333); 4.31 nested them under 'if s3.httpsPort' and we ship
   httpsPort=0, so s3 spoke HTTP while the HTTPS probes, the ingress
   backend-protocol and the COSI sidecar endpoint all expected HTTPS
   ('server gave HTTP response to HTTPS client'). Restore the 4.05
   behaviour via patch.

2. COSI provisioner ServiceAccount mismatch. cosi-service-account.yaml
   and the ClusterRoleBinding name the SA
   <serviceAccountName>-objectstorage-provisioner, but the Deployment
   referenced componentName (<release>-objectstorage-provisioner). When
   serviceAccountName != release name (tenant-root-seaweedfs vs
   seaweedfs-system) the Deployment could not create pods
   ('serviceaccount not found'). Align the Deployment with the SA + binding.

Both fixes are vendored as patches re-applied by 'make update', and
covered by helm-unittest.

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Andrei Kvapil <[email protected]>
Signed-off-by: Ivan Okhotnikov <[email protected]>
@github-actions github-actions Bot added size/XL This PR changes 500-999 lines, ignoring generated files and removed size/S This PR changes 10-29 lines, ignoring generated files labels Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/cmd/server/openapi.go`:
- Around line 115-135: The sanitizeBooleanAdditionalProperties function in the
openapi.go file currently only traverses Properties, Items, combinators (AllOf,
AnyOf, OneOf), and Not fields, but it is missing traversal for
PatternProperties, AdditionalItems.Schema, and Definitions fields that are also
part of spec.SchemaProps. Add recursive sanitization calls for these three
missing fields to ensure boolean-form additionalProperties nested anywhere in a
user-supplied schema cannot bypass sanitization. Additionally, update the
hasBooleanAdditionalProperties test helper function to mirror the same full
coverage by checking these same three additional fields alongside the existing
checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bb819ad0-cd2a-45a9-8666-c6c46a4b6a16

📥 Commits

Reviewing files that changed from the base of the PR and between 0794c85 and c402f95.

📒 Files selected for processing (8)
  • packages/system/seaweedfs/Makefile
  • packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml
  • packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml
  • packages/system/seaweedfs/patches/cosi-provisioner-sa-name.patch
  • packages/system/seaweedfs/patches/s3-tls-main-port.patch
  • packages/system/seaweedfs/tests/s3_tls_cosi_sa_test.yaml
  • pkg/cmd/server/openapi.go
  • pkg/cmd/server/openapi_test.go

Comment thread pkg/cmd/server/openapi.go
Comment on lines +115 to +135
for k := range s.Properties {
prop := s.Properties[k]
sanitizeBooleanAdditionalProperties(&prop)
s.Properties[k] = prop
}
if s.Items != nil {
sanitizeBooleanAdditionalProperties(s.Items.Schema)
for i := range s.Items.Schemas {
sanitizeBooleanAdditionalProperties(&s.Items.Schemas[i])
}
}
for i := range s.AllOf {
sanitizeBooleanAdditionalProperties(&s.AllOf[i])
}
for i := range s.AnyOf {
sanitizeBooleanAdditionalProperties(&s.AnyOf[i])
}
for i := range s.OneOf {
sanitizeBooleanAdditionalProperties(&s.OneOf[i])
}
sanitizeBooleanAdditionalProperties(s.Not)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

gopath="$(go env GOPATH 2>/dev/null || true)"
if [ -n "$gopath" ] && [ -d "$gopath/pkg/mod" ]; then
  rg -n 'type SchemaProps struct|PatternProperties|AdditionalItems|Definitions' \
    "$gopath/pkg/mod/k8s.io/kube-openapi"* \
    "$gopath/pkg/mod/github.com/go-openapi/spec"* 2>/dev/null || true
fi

rg -n 'sanitizeBooleanAdditionalProperties|hasBooleanAdditionalProperties|PatternProperties|AdditionalItems|Definitions' --type=go

Repository: cozystack/cozystack

Length of output: 5326


🏁 Script executed:

# First, let's look at the sanitizeBooleanAdditionalProperties function in detail
cat -n pkg/cmd/server/openapi.go | head -150 | tail -70

Repository: cozystack/cozystack

Length of output: 3204


🏁 Script executed:

# Now let's look at the hasBooleanAdditionalProperties test helper
cat -n pkg/cmd/server/openapi_test.go | sed -n '170,220p'

Repository: cozystack/cozystack

Length of output: 2075


🏁 Script executed:

# Let's search for spec.SchemaProps definition to understand the schema structure
rg -A 50 'type SchemaProps struct' --type=go 2>/dev/null | head -80

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Check imports in openapi.go
head -20 pkg/cmd/server/openapi.go

Repository: cozystack/cozystack

Length of output: 637


🏁 Script executed:

# Search for any reference to PatternProperties, AdditionalItems in the codebase
rg 'PatternProperties|AdditionalItems' --type=go -B 2 -A 2

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Look for schema field assignments to understand what's available
rg 's\.(PatternProperties|AdditionalItems|Definitions)' --type=go

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Let me search for the test file to see what fields are actually being tested
cat -n pkg/cmd/server/openapi_test.go | head -280 | tail -100

Repository: cozystack/cozystack

Length of output: 5058


🏁 Script executed:

# Search for any schema construction to see what fields are used
rg 'spec\.Schema\{' --type=go -A 5 | head -100

Repository: cozystack/cozystack

Length of output: 8240


🏁 Script executed:

# Let's check the Definitions field specifically in the test
rg -n 'Definitions' pkg/cmd/server/openapi_test.go -B 2 -A 2

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Search for web documentation about spec.SchemaProps
web_search
k8s.io kube-openapi spec.SchemaProps fields PatternProperties AdditionalItems Definitions

Repository: cozystack/cozystack

Length of output: 159


🏁 Script executed:

# Check if there are any comments in the code about which fields are supported
rg -i 'patternproperties|additionalitems|definitions' pkg/cmd/server/ -B 2 -A 2

Repository: cozystack/cozystack

Length of output: 3165


🏁 Script executed:

# Look at the full test file to understand what's covered
wc -l pkg/cmd/server/openapi_test.go

Repository: cozystack/cozystack

Length of output: 98


🌐 Web query:

k8s.io kube-openapi validation spec SchemaProps struct fields

💡 Result:

In the k8s.io/kube-openapi library, the SchemaProps struct defines the core validation properties for an OpenAPI schema [1]. It is a central component of the Schema struct, which represents an OpenAPI schema definition [1][2]. The SchemaProps struct contains the following fields [1]: - Ref: A reference to another schema definition (internal to the spec) [1]. - Schema: The URI of the schema, often used for identifying the JSON Schema version [1]. - Description: A short description of the field [1]. - Type: Specifies the data type(s) of the schema, represented as a StringOrArray [1]. - Nullable: A boolean indicating if the value can be null [1]. - Format: A string specifying the format of the data (e.g., "date-time", "int64") [1]. - Title: The title of the schema [1]. - Default: The default value for the field [1]. - Maximum / Minimum: Pointers to float64 values defining range boundaries [1]. - ExclusiveMaximum / ExclusiveMinimum: Booleans indicating if the boundaries are exclusive [1]. - MaxLength / MinLength: Pointers to int64 values for string length constraints [1]. - Pattern: A regular expression pattern for string validation [1]. - MaxItems / MinItems: Pointers to int64 values for array length constraints [1]. - UniqueItems: A boolean indicating if array items must be unique [1]. - MultipleOf: A pointer to a float64 value for numeric divisibility [1]. - Enum: A slice of allowed values [1]. - MaxProperties / MinProperties: Pointers to int64 values for object property count constraints [1]. - Required: A slice of strings listing required property names [1]. - Items: A pointer to a SchemaOrArray for array item definitions [1]. - AllOf, OneOf, AnyOf: Slices of Schema objects for composition [1]. - Not: A pointer to a Schema object for exclusion validation [1]. - Properties: A map of string keys to Schema objects defining object properties [1]. - AdditionalProperties: A SchemaOrBool type defining the allowed schema for additional object properties [1]. This structure is used extensively within Kubernetes for generating and validating OpenAPI specifications dynamically [3][4]. Developers typically interact with this struct when defining custom OpenAPI definitions for Go types using the k8s.io/kube-openapi/pkg/common package [4].

Citations:


🏁 Script executed:

# Let's check what version of kube-openapi might be used
rg 'kube-openapi' go.mod

Repository: cozystack/cozystack

Length of output: 119


🏁 Script executed:

# Check if there are any TODO comments or notes about incomplete coverage
rg -i 'todo|fixme|incomplete|missing' pkg/cmd/server/openapi.go -B 2 -A 2

Repository: cozystack/cozystack

Length of output: 45


🌐 Web query:

kube-openapi SchemaProps PatternProperties AdditionalItems Definitions fields

💡 Result:

In the context of the kube-openapi library (and the underlying go-openapi/spec model it frequently references), the SchemaProps struct defines the core properties of a JSON Schema [1][2]. Key fields within SchemaProps include: PatternProperties: A map where keys are regular expressions and values are Schema objects, used to validate properties matching the specified pattern [3]. AdditionalItems: Used for array validation; it specifies the schema for items that do not match the main items definition [3]. In many implementations, it is represented as a JSONSchemaPropsOrBool, allowing either a full schema or a boolean to enable/disable additional items [3]. Definitions: While often part of the broader OpenAPI/JSON Schema structure, definitions act as a map (map[string]JSONSchemaProps) for storing reusable sub-schemas that can be referenced elsewhere via $ref [3]. Additional fields commonly found within the SchemaProps struct include: Properties: A map of property names to their respective Schema definitions [3][1]. Required: A list of strings identifying which properties are mandatory [1]. Items: Defines the schema for elements in an array, represented as a SchemaOrArray type [1]. Type, Format, Description: Basic metadata fields for schema validation and documentation [1]. AllOf, OneOf, AnyOf, Not: Fields used for schema composition and logical constraints [4][1]. The kube-openapi library is primarily used for generating and serving Kubernetes API specifications, often relying on the struct tags defined in these packages to handle JSON marshaling and unmarshaling of Kubernetes resource definitions [5][6]. Note that the ID field in some versions of this struct is included primarily for compatibility with broader JSON Schema specifications (which use 'id' for $ref resolution) even if it is not explicitly part of the standard OpenAPI v2 specification [7][8].

Citations:


🏁 Script executed:

# Let's look at the current test cases to see if they test for the missing fields
cat -n pkg/cmd/server/openapi_test.go | sed -n '230,280p'

Repository: cozystack/cozystack

Length of output: 2758


🏁 Script executed:

# Check if spec.SchemaProps actually has these fields by looking at the GitHub source
# Let's search for any usage of these fields in a different context
rg '\.(PatternProperties|AdditionalItems|Definitions)\s*=' --type=go | head -20

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Let's check the actual kube-openapi source to verify the fields exist
# by looking at the GitHub repository for that specific version
python3 << 'PY'
# The version string suggests it's a pseudo-version pointing to a specific commit
# Let's parse what we know and search for confirmation in docs or code
version_str = "v0.0.0-20250814151709-d7b6acb124c3"
# Extract timestamp: 20250814151709 = 2025-08-14 15:17:09
# Extract commit: d7b6acb124c3
print("kube-openapi version: " + version_str)
print("Date: 2025-08-14")
print("Commit: d7b6acb124c3")
PY

Repository: cozystack/cozystack

Length of output: 158


🏁 Script executed:

# Let's verify by checking if the code even compiles/has references to these fields
# Look for any schema building code that might use these fields
rg 'spec\.Schema' pkg/cmd/server/ -A 3 | grep -E '(PatternProperties|AdditionalItems|Definitions)' | head -20

Repository: cozystack/cozystack

Length of output: 45


🏁 Script executed:

# Let's examine the full sanitizeBooleanAdditionalProperties and hasBooleanAdditionalProperties side by side
echo "=== sanitizeBooleanAdditionalProperties ===" && \
sed -n '102,136p' pkg/cmd/server/openapi.go && \
echo "" && \
echo "=== hasBooleanAdditionalProperties ===" && \
sed -n '174,210p' pkg/cmd/server/openapi_test.go

Repository: cozystack/cozystack

Length of output: 1975


Extend schema traversal to cover PatternProperties, AdditionalItems, and Definitions fields.

The sanitizer currently traverses properties, items, additionalProperties.Schema, combinators, and not, but the underlying kube-openapi spec.SchemaProps struct also exposes patternProperties, additionalItems.Schema, and definitions fields. A user-supplied schema with boolean-form additionalProperties nested under any of these uncovered fields would bypass sanitization and still be marshaled into served OpenAPI, leaving the nil-inner-schema shape this PR is trying to eliminate. Update both the sanitizer and the hasBooleanAdditionalProperties test helper to mirror the full coverage.

Suggested recursion coverage
 	if s.Items != nil {
 		sanitizeBooleanAdditionalProperties(s.Items.Schema)
 		for i := range s.Items.Schemas {
 			sanitizeBooleanAdditionalProperties(&s.Items.Schemas[i])
 		}
 	}
+	if s.AdditionalItems != nil && s.AdditionalItems.Schema != nil {
+		sanitizeBooleanAdditionalProperties(s.AdditionalItems.Schema)
+	}
+	for k := range s.PatternProperties {
+		prop := s.PatternProperties[k]
+		sanitizeBooleanAdditionalProperties(&prop)
+		s.PatternProperties[k] = prop
+	}
+	for k := range s.Definitions {
+		def := s.Definitions[k]
+		sanitizeBooleanAdditionalProperties(&def)
+		s.Definitions[k] = def
+	}
 	for i := range s.AllOf {
 		sanitizeBooleanAdditionalProperties(&s.AllOf[i])
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for k := range s.Properties {
prop := s.Properties[k]
sanitizeBooleanAdditionalProperties(&prop)
s.Properties[k] = prop
}
if s.Items != nil {
sanitizeBooleanAdditionalProperties(s.Items.Schema)
for i := range s.Items.Schemas {
sanitizeBooleanAdditionalProperties(&s.Items.Schemas[i])
}
}
for i := range s.AllOf {
sanitizeBooleanAdditionalProperties(&s.AllOf[i])
}
for i := range s.AnyOf {
sanitizeBooleanAdditionalProperties(&s.AnyOf[i])
}
for i := range s.OneOf {
sanitizeBooleanAdditionalProperties(&s.OneOf[i])
}
sanitizeBooleanAdditionalProperties(s.Not)
for k := range s.Properties {
prop := s.Properties[k]
sanitizeBooleanAdditionalProperties(&prop)
s.Properties[k] = prop
}
if s.Items != nil {
sanitizeBooleanAdditionalProperties(s.Items.Schema)
for i := range s.Items.Schemas {
sanitizeBooleanAdditionalProperties(&s.Items.Schemas[i])
}
}
if s.AdditionalItems != nil && s.AdditionalItems.Schema != nil {
sanitizeBooleanAdditionalProperties(s.AdditionalItems.Schema)
}
for k := range s.PatternProperties {
prop := s.PatternProperties[k]
sanitizeBooleanAdditionalProperties(&prop)
s.PatternProperties[k] = prop
}
for k := range s.Definitions {
def := s.Definitions[k]
sanitizeBooleanAdditionalProperties(&def)
s.Definitions[k] = def
}
for i := range s.AllOf {
sanitizeBooleanAdditionalProperties(&s.AllOf[i])
}
for i := range s.AnyOf {
sanitizeBooleanAdditionalProperties(&s.AnyOf[i])
}
for i := range s.OneOf {
sanitizeBooleanAdditionalProperties(&s.OneOf[i])
}
sanitizeBooleanAdditionalProperties(s.Not)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/cmd/server/openapi.go` around lines 115 - 135, The
sanitizeBooleanAdditionalProperties function in the openapi.go file currently
only traverses Properties, Items, combinators (AllOf, AnyOf, OneOf), and Not
fields, but it is missing traversal for PatternProperties,
AdditionalItems.Schema, and Definitions fields that are also part of
spec.SchemaProps. Add recursive sanitization calls for these three missing
fields to ensure boolean-form additionalProperties nested anywhere in a
user-supplied schema cannot bypass sanitization. Additionally, update the
hasBooleanAdditionalProperties test helper function to mirror the same full
coverage by checking these same three additional fields alongside the existing
checks.

…lass

The seaweedfs 4.31 upstream bump (#2834) rewrote
packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-bucket-class.yaml
from scratch and silently dropped the supplementary COSI resources
that cozystack ships on top of the upstream chart:

- BucketClass {name}-lock (object lock, COMPLIANCE mode, 365 days
  retention) — used by apps that store immutable backups
- BucketAccessClass {name} parameters.accessPolicy: readwrite — the
  explicit grant for the default access class
- BucketAccessClass {name}-readonly (accessPolicy: readonly) — used
  by every Bucket app that declares readonly users

apps/bucket still renders BucketAccess resources that reference
{name}-readonly, but the class no longer exists, so the COSI
controller never picks the BucketAccess up: no finalizer is added,
status.accessGranted stays empty, and the bucket E2E test waits 300s
and times out on the viewer access. The admin (readwrite) access
class still works because it falls back to the default BAC.

Restore the three resources so the system chart again matches the
shape that packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml
already ships for the client topology (where this never regressed).

Signed-off-by: Ivan Okhotnikov <[email protected]>
The seaweedfs 4.31 upstream bump (#2834) switched the s3 Service name
from "$chartname-s3" (built with the seaweedfs.name helper, evaluates
to "seaweedfs-s3") to the seaweedfs.componentName helper, which is
release-name based and now evaluates to "$release-s3" — "seaweedfs-
system-s3" for the tenant-root deployment.

The bats E2E asset hack/e2e-apps/bucket.bats hard-codes
"service/seaweedfs-s3" for the port-forward that sets up its
S3 client; backup-controller and other in-cluster consumers also
referenced the legacy name. After the bump, the legacy Service is
gone and the port-forward immediately exits, the test then times out
on the 30-second nc poll for localhost:8333.

Restore the legacy Service name. Internal references inside the chart
(s3-deployment -filer=, etc) keep using componentName for the filer
endpoint, so this change only re-exposes the public-facing name
without touching the internal topology.

Signed-off-by: Ivan Okhotnikov <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml`:
- Line 5: The change to the name field in the s3-service.yaml file has been
committed directly to the vendored SeaweedFS Helm chart content, but this will
be overwritten when make update re-vendors the upstream charts. Instead, create
a new patch file in packages/system/seaweedfs/patches/ (for example,
s3-service-name.patch) that contains this change to the template name field,
following the established pattern of existing patches like
cosi-provisioner-sa-name.patch and s3-tls-main-port.patch. Then restore the
vendored s3-service.yaml template file back to its upstream state so the fix is
applied via the patch file during the chart update process rather than as a
direct modification.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 76973cd4-cd9b-48e7-b606-d3486f0f5b87

📥 Commits

Reviewing files that changed from the base of the PR and between 700149e and 634a5c5.

📒 Files selected for processing (1)
  • packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml

kind: Service
metadata:
name: {{ include "seaweedfs.componentName" (list . "s3") }}
name: {{ template "seaweedfs.name" . }}-s3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the S3 service name change is applied via patch

# Check if a patch exists for the s3-service.yaml file
echo "=== Checking for patches that modify s3-service.yaml ==="
fd -t f '\.patch$' packages/system/seaweedfs/patches/ --exec rg -l 's3-service\.yaml'

# Check the Makefile for patch application
echo -e "\n=== Checking Makefile for patch application ==="
rg -A5 -B5 'patch|s3-service' packages/system/seaweedfs/Makefile

# Verify git status shows this file is not directly modified
echo -e "\n=== Git status of the vendored chart file ==="
git status packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml

Repository: cozystack/cozystack

Length of output: 1022


🏁 Script executed:

#!/bin/bash
# Get git diff for the s3-service.yaml file and check patch context

echo "=== Git diff for s3-service.yaml ==="
git diff HEAD packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml | head -50

echo -e "\n=== All patch files in packages/system/seaweedfs/patches/ ==="
ls -la packages/system/seaweedfs/patches/

echo -e "\n=== Content of patches directory ==="
find packages/system/seaweedfs/patches/ -type f -exec echo "File: {}" \; -exec head -5 {} \;

echo -e "\n=== Check if s3-service.yaml is in any patch ==="
grep -r "s3-service" packages/system/seaweedfs/patches/ 2>/dev/null || echo "No matches found"

echo -e "\n=== Check git log for this file ==="
git log --oneline -n 5 packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml

Repository: cozystack/cozystack

Length of output: 3216


Extract this change into a proper patch file rather than committing directly to vendored content.

The s3-service.yaml change is currently committed directly to the vendored SeaweedFS Helm chart, but it should be applied via a patch file following the established pattern in packages/system/seaweedfs/patches/. The Makefile already applies 5 patches during the update process (cosi-provisioner-sa-name.patch, disable-ca-key-rotation.patch, resize-api-server-annotation.diff, s3-tls-main-port.patch, and retention-policy-delete.yaml). This direct edit will be overwritten when make update re-vendors the upstream charts.

Create a new patch file (e.g., packages/system/seaweedfs/patches/s3-service-name.patch) with this change and restore the vendored template file to upstream state. This ensures the fix persists across chart updates and maintains the architectural pattern for managing vendored content.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml` at
line 5, The change to the name field in the s3-service.yaml file has been
committed directly to the vendored SeaweedFS Helm chart content, but this will
be overwritten when make update re-vendors the upstream charts. Instead, create
a new patch file in packages/system/seaweedfs/patches/ (for example,
s3-service-name.patch) that contains this change to the template name field,
following the established pattern of existing patches like
cosi-provisioner-sa-name.patch and s3-tls-main-port.patch. Then restore the
vendored s3-service.yaml template file back to its upstream state so the fix is
applied via the patch file during the chart update process rather than as a
direct modification.

Source: Learnings

IvanHunters and others added 5 commits June 15, 2026 20:09
`kubectl port-forward service/seaweedfs-s3 -n tenant-root 8333:8333`
binds the listener to 127.0.0.1 only — it has no IPv6 listener. The
runner's getaddrinfo resolves `localhost` to `::1` first, and `mc`
keeps a single connection target across the whole alias, so the
initial `mc alias set` (which only sets credentials, no network I/O)
silently succeeds while the subsequent `mc cp` upload tries
`https://[::1]:8333` and gets immediate `connection refused`. The
test then exits with the misleading bucket-test failure even though
the S3 backend, credentials, and bucket all reconciled correctly.

Use a literal IPv4 address (`127.0.0.1`) for the mc aliases and the
`nc -z` readiness probe so the test no longer depends on the
runner's IPv4/IPv6 resolution policy.

Signed-off-by: Ivan Okhotnikov <[email protected]>
The test used to wrap kubectl port-forward in a transient subshell:

  bash -c 'timeout 100s kubectl port-forward ... > /dev/null 2>&1 &'

The wrapper subshell exits immediately after backgrounding the
kubectl process, the kubectl child is reparented to PID 1, and on
the GitHub-hosted runner it gets reaped between the `nc -z` readiness
probe and the first `mc cp` call. The captured failure looks like

  + bash -c timeout 100s kubectl port-forward ...
  + timeout 30 sh -ec until nc -z localhost 8333; do sleep 1; done
  + mc alias set rw-user https://127.0.0.1:8333 ... --insecure
  Added `rw-user` successfully.
  + mc cp --insecure /tmp/rw-test.txt rw-user/$BUCKET/rw-test.txt
  mc: <ERROR> Put "https://127.0.0.1:8333/$BUCKET/...":
    dial tcp 127.0.0.1:8333: connect: connection refused

even though every S3 resource (Bucket, BucketClaim, both BucketAccess)
is Ready/Granted=true at that point and the seaweedfs-s3 Service is
healthy in tenant-root.

Run kubectl port-forward as a job of the calling shell, capture its
PID, and tear it down via a bats RETURN trap. The trap is enough on
its own: the test no longer needs the outer `timeout 100s` belt
because the port-forward will be killed when the test function
returns, even on failure. Also switch the readiness probe to
127.0.0.1 to match the mc alias and avoid any IPv6 resolution path
on hosts where kubectl binds IPv4 only.

Signed-off-by: Ivan Okhotnikov <[email protected]>
The previous attempt added a bash `trap '...' RETURN` to clean up
kubectl port-forward when the test function returned. cozytest.sh
sources its converted bats test bodies into the runner shell, which
on the GitHub-hosted Linux runner is /bin/sh -> dash. dash does not
implement the bash-specific RETURN pseudo-signal, so the trap
command exits non-zero, the surrounding `set -eu` aborts the test
body immediately, and the captured output stops two lines after
`name=test` with no other diagnostic — the test never reaches the
mc S3 operations at all.

Drop the trap and rely on cozytest.sh's existing process-group
cleanup: when the test function returns, the leftover port-forward
job in the same group is terminated. This restores POSIX shell
compatibility while keeping the lifecycle fix from the previous
commit (no `bash -c '... &'` wrapper, port-forward stays alive
through the mc operations because it is a child of the calling
shell, not of a transient subshell that exits immediately).

Signed-off-by: Ivan Okhotnikov <[email protected]>
Cozystack overrides the upstream seaweedfs volumeSizeLimitMB from
1000 to 30000 (30 GB), but the e2e sandbox provisions only a 10 GiB
PVC per volume server. With maxVolumes=0 (auto), seaweedfs computes
maxVolumes as int(10240 / 30000) → 0, then rounds up to 1, so each
volume server can host exactly 1 logical volume.

With defaultReplication=001 (one replica on a different node within
the same rack) two volume servers share that single volume, giving
the cluster a hard limit of one writable collection at a time.

Since #2716 added a default bucket-cozy-backups Bucket to every
tenant-root, that bucket now grabs the only slot on install. Any
second collection — the bucket E2E (bucket-test in tenant-test),
a tenant app's own bucket, etc. — sits in 'assign volume: No
writable volumes' forever, and mc cp hangs until the test times
out. Master logs reflect this clearly:

    failed to find writable volumes for collection:bucket-...
      replication:001 ttl:
    error: No writable volumes and no free volumes left
    topo failed to pick 1 from 0 node candidates
    volume_growth.go:135 create 6 volume, created 0:
      Not enough data nodes found!

Lower volumeSizeLimitMB back to the upstream chart default of 1000,
which makes a 10 GiB PVC fit ~10 logical volumes per server and
unblocks all per-collection bucket workloads on small sandboxes.
Production clusters still get plenty of headroom — volume size is a
soft cap, not a preallocation.

Signed-off-by: Ivan Okhotnikov <[email protected]>
A churn-heavy platform install intermittently wedges a pod in
ContainerCreating because the cilium-agent rejects its sandbox with
'[PUT /endpoint/{id}][400] putEndpointIdInvalid "IP ipv4:<X> is already
in use"', repeated until the agent restarts or the install times out.
The disputed IP has no live owner: IPAM and the ipcache released it, but
the agent's in-memory endpointManager still holds a stale Endpoint from a
previously-deleted pod whose CNI DEL was skipped or raced (so
removeReferencesLocked never ran). Neither the operator's CiliumEndpoint
GC nor the agent's veth-based endpoint GC can reap it. This surfaced as
~6 of the post-#2558 e2e failures, each on a different victim pod
(velero node-agent, fluent-bit, fdb-operator, cdi-operator, capi
bootstrap), failing PRs unrelated to the change under test. Tracked
upstream at cilium/cilium#38313 (closed stale); no released or
pre-release Cilium fixes it and no flag disables it.

hack/e2e-cilium-endpoint-leak-healer.sh runs as a file-scoped background
watchdog (setup_file/teardown_file). It detects a wedged pod, confirms
the IP is a true orphan -- an endpoint in the owning node's registry
holds it, that endpoint backs no live Running pod, and a different pod is
wedged requesting the same IP -- then evicts only that endpoint via
'cilium-dbg endpoint disconnect ipv4:<X>' (DELETE /endpoint/{id} ->
unexpose -> removeReferencesLocked). Blast radius is one dead endpoint,
not an agent restart. It is read-only until an orphan is positively
confirmed and refuses (loudly) to touch an endpoint backing a live pod,
so a genuine duplicate-IP bug stays visible rather than masked.

This is an interim CI mitigation, not a product fix; remove the script
and the bats hooks once a fixed Cilium ships.

Assisted-By: Claude <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
Signed-off-by: Ivan Okhotnikov <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci Issues or PRs related to CI workflows, GitHub Actions, automation area/testing Issues or PRs related to testing (e2e, bats, unit tests) debug Debugging in progress do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress kind/failing-test Categorizes issue or PR as related to a consistently or frequently failing test lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor size/XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants