Skip to content

OSAC-3273, OSAC-3280: Volume private API, DB migration, and CRD types - #201

Merged
omer-vishlitzky merged 7 commits into
osac-project:mainfrom
akshaynadkarni:feat/OSAC-2872-volume-api-crd
Aug 11, 2026
Merged

OSAC-3273, OSAC-3280: Volume private API, DB migration, and CRD types#201
omer-vishlitzky merged 7 commits into
osac-project:mainfrom
akshaynadkarni:feat/OSAC-2872-volume-api-crd

Conversation

@akshaynadkarni

@akshaynadkarni akshaynadkarni commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the Volume resource data model and private API to the fulfillment-service,
with Volume CRD types in osac-operator. This is the foundation for the storage
control plane feature (OSAC-2872).

Why

The storage control plane needs a Volume resource to track block storage provisioned on
backend storage arrays. This PR establishes the proto definitions, database schema,
passthrough API server, and event integration. The Volume API serves both PVC-driven
flows (CSI driver creates volumes in response to PVCs) and API-driven flows (CSP admin
creates standalone volumes as inventory). Cluster association is intentionally not part
of the Volume spec: it will be tracked via status or a future attach/detach model
(OSAC-984), keeping the volume representation consistent across all creation flows.

What's included

fulfillment-service

  • Proto: volume_type.proto (Volume, VolumeSpec, VolumeStatus, VolumeState,
    VolumeAccessMode enum, PVCReference, PVReference) and volumes_service.proto
    (List, Get, Create, Update, Delete, Signal RPCs with REST transcoding)
  • Shared proto: storage_common_type.proto with StorageProtocol enum (moved from
    storage_tier_type.proto to avoid false dependency between Volume and StorageTier)
  • Validation: buf.validate annotations on spec fields (storage_tier min_len,
    size_gib gt 0, access_mode defined_only) + server-side validateVolumeCreate
  • Event: Volume added to Event oneof (field 41)
  • DB migration (94): volumes + archived_volumes tables, unique name per tenant,
    tenant/project FKs, immutability triggers on id/name/tenant/project
  • Server: private_volumes_server.go using GenericServer pattern, Create validates
    required fields and sets initial state to CREATING
  • Table rendering: Private Volume table with ID, NAME, TENANT, TIER, SIZE, BACKEND, STATE
  • Registration: gRPC server + REST gateway

osac-operator

  • CRD types: VolumeSpec (storageTier, sizeGiB, accessMode as enum, pvcRef), VolumeStatus
    (phase, conditions with list-map markers, vendorVolumeID, backend, protocol as enum, hub,
    pvcRef, pvRef)
  • Phases: Progressing, Ready, Failed, Deleting
  • Conditions: VendorProvisioned
  • Immutability: XValidation rules on all spec fields + spec-level pvcRef removal guard
  • Constants: osac-volume namespace, volume/volume-uuid labels, volume/feedback/cleanup finalizers
  • Print columns: Tier, Size, Access, Phase (default), Backend, VendorID (wide)
  • Scheme registration, generated CRD manifest, Helm chart CRD sync

Not in this PR

  • Volume reconciler (fulfillment-service)
  • Volume controller and feedback controller (osac-operator)
  • Storage logic layer (tier resolution, OPA policy)
  • StorageControlPlane internal API (PublishVolume/UnpublishVolume)
  • Server-side spec immutability enforcement on Update (controller PR)
  • CLI commands

Testing

# buf lint passes
cd fulfillment-service && buf lint

# All fulfillment-service unit tests pass (85 suites)
go run github.com/onsi/ginkgo/v2/ginkgo run -r internal
# Ginkgo ran 85 suites in 7m6s - Test Suite Passed

# osac-operator: lint 0 issues, all tests pass
cd osac-operator && make lint test

Ticket

Feature: OSAC-2872 (Storage Control Plane)

Epics:

Tasks covered in this PR:

  • OSAC-3274: Volume proto definitions
  • OSAC-3275: Volume API server and DB migration
  • OSAC-3281: Volume CRD types, conditions, labels, and finalizers

Userflow: OSAC-3371 (hub PVC create happy path)


Signed-off-by: akshaynadkarni 25892229+akshaynadkarni@users.noreply.github.com
Assisted-by: Cursor/Claude

@openshift-ci-robot

openshift-ci-robot commented Aug 7, 2026

Copy link
Copy Markdown

@akshaynadkarni: This pull request references OSAC-2872 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the feature to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

OSAC-2872: Adds the Volume resource data model and private API to the fulfillment-service,
with Volume CRD types in osac-operator to follow. This is the foundation for the storage
control plane feature.

Work in progress: Volume CRD types (osac-operator) will be added in a follow-up commit
on this branch.

Why

The storage control plane needs a Volume resource to track block storage provisioned on
backend storage arrays. This PR establishes the proto definitions, database schema,
passthrough API server, and event integration. The Volume API serves both PVC-driven
flows (CSI driver creates volumes in response to PVCs) and API-driven flows (CSP admin
creates standalone volumes as inventory).

What's included

fulfillment-service

  • Proto: volume_type.proto (Volume, VolumeSpec, VolumeStatus, VolumeState, PVCReference,
    PVReference) and volumes_service.proto (List, Get, Create, Update, Delete, Signal RPCs
    with REST transcoding)
  • Event: Volume added to Event oneof (field 41)
  • DB migration (93): volumes + archived_volumes tables, unique name per tenant, tenant/project
    FKs, immutability triggers on id/name/tenant/project
  • Server: private_volumes_server.go using GenericServer pattern, Create sets initial state
    to CREATING
  • Table rendering: Private Volume table with ID, NAME, TENANT, TIER, SIZE, CLUSTER, BACKEND, STATE
  • Registration: gRPC server + REST gateway

Not in this PR

  • Volume reconciler (fulfillment-service)
  • Volume CRD controller and feedback controller (osac-operator)
  • Storage logic layer (tier resolution, OPA policy)
  • StorageControlPlane internal API (PublishVolume/UnpublishVolume)
  • CLI commands

Testing

# buf lint passes
cd fulfillment-service && buf lint

# All 1539 server tests pass (including new Volume tests)
go run github.com/onsi/ginkgo/v2/ginkgo run internal/servers
# Ran 1539 of 1539 Specs in 166.495 seconds
# SUCCESS! -- 1539 Passed | 0 Failed

Ticket

OSAC-2872 (parent feature), OSAC-3273 (Volume API epic), OSAC-3280 (Volume CRD epic)

Userflow: OSAC-3371 (hub PVC create happy path)


Signed-off-by: akshaynadkarni 25892229+akshaynadkarni@users.noreply.github.com
Assisted-by: Cursor/Claude

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot added the approved label Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

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

Adds private Volume protobuf contracts, database persistence, fulfillment-service CRUD and signal handling, REST/gRPC registration, table rendering, and the Kubernetes Volume API with CRDs.

Changes

Volume contracts

Layer / File(s) Summary
Volume protobuf contracts
fulfillment-service/proto/private/osac/private/v1/storage_common_type.proto, fulfillment-service/proto/private/osac/private/v1/storage_tier_type.proto, fulfillment-service/proto/private/osac/private/v1/volume_type.proto, fulfillment-service/proto/private/osac/private/v1/volumes_service.proto, fulfillment-service/proto/private/osac/private/v1/event_type.proto
Defines storage protocols, Volume lifecycle states, specifications, status, references, CRUD and signal RPCs, HTTP mappings, and Volume event payloads.

Volume persistence rules

Layer / File(s) Summary
Volume persistence rules
fulfillment-service/internal/database/migrations/94_create_volumes_tables.up.sql, fulfillment-service/internal/database/migrations/94_create_volumes_tables_test.go, fulfillment-service/internal/database/migrations.sha256
Creates active and archived volume tables with tenant ownership, uniqueness, immutability, indexes, migration tests, and an updated checksum.

Operator Volume resource

Layer / File(s) Summary
Operator Volume resource
osac-operator/api/v1alpha1/*, osac-operator/config/crd/bases/*, osac-operator/charts/operator-crds/templates/*
Adds Volume API types, validation, constants, scheme registration, deepcopy methods, and namespaced CRD schemas with status support and printer columns.

Private volumes service

Layer / File(s) Summary
Private volumes service
fulfillment-service/internal/servers/private_volumes_server.go, fulfillment-service/internal/servers/private_volumes_server_test.go
Adds the builder-backed server and delegates List, Get, Create, Update, Delete, and Signal operations. Create normalizes status, sets CREATING, and clears caller-provided IDs. Tests cover validation, CRUD, filtering, ordering, updates, uniqueness, and signaling.

Volume API exposure and rendering

Layer / File(s) Summary
Volume API exposure and rendering
fulfillment-service/internal/cmd/service/start/grpcserver/start_grpc_server_cmd.go, fulfillment-service/internal/cmd/service/start/restgateway/start_rest_gateway_cmd.go, fulfillment-service/internal/rendering/tables/osac.private.v1.Volume.yaml
Registers the private volumes gRPC and REST handlers and adds table columns for Volume metadata, specification, backend, size, and state.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client as Volumes API client
  participant Gateway as REST gateway
  participant Server as PrivateVolumesServer
  participant Generic as GenericServer
  Client->>Gateway: Send Volume API request
  Gateway->>Server: Route request to Volumes RPC
  Server->>Generic: Delegate volume operation
  Generic-->>Server: Return response or error
  Server-->>Gateway: Return RPC response
  Gateway-->>Client: Return HTTP response
Loading

Possibly related PRs

  • osac-project/osac#40: Adds an analogous private gRPC CRUD and Signal service using a builder-configured GenericServer.
  • osac-project/osac#141: Adds the CSI VolumeClient that consumes the fulfillment-service Volumes API.
  • osac-project/osac#193: Adds validation behavior inherited by PrivateVolumesServer.Create.

Suggested labels: storage

Suggested reviewers: avishayt, eliorerz


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error The new generated Volume gateway logs the caller-supplied endpoint with grpclog.Errorf, which may expose an internal hostname. Remove the raw endpoint from this error log, or log only a sanitized value; update the generator/template so regeneration preserves the fix.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (9 passed)
Check name Status Explanation
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.
No-Hardcoded-Secrets ✅ Passed The full merge-base diff contains no hardcoded credentials, secret-named literal assignments, private-key material, embedded-credential URLs, or recognized vendor token formats; long literals are g...
No-Weak-Crypto ✅ Passed The complete PR diff adds no MD5, SHA-1, DES, 3DES, RC4, Blowfish, ECB, weak crypto API, custom crypto, or secret-comparison code.
No-Injection-Vectors ✅ Passed No listed injection sink was added. The only formatted SQL is a migration test using a fixed table name sanitized by pgx.Identifier; all data uses bound parameters.
Container-Privileges ✅ Passed The PR adds only Volume CRD manifests; the full PR diff introduces no privileged, host namespace, SYS_ADMIN, root, or allowPrivilegeEscalation settings.
Ai-Attribution ✅ Passed AI use is disclosed as Cursor/Claude, and all six OSAC-2872 commits include Assisted-by: Cursor/Claude; no AI Co-Authored-By trailer was found.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main changes: the Volume private API, database migration, and CRD types.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@akshaynadkarni

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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
`@fulfillment-service/internal/database/migrations/93_create_volumes_tables_test.go`:
- Around line 141-158: Update the immutable-column test around the existing id,
name, and tenant updates to assert each error has PostgreSQL SQLSTATE Z0001 from
check_immutable_columns(), rather than only asserting an error occurred. Add a
corresponding project update using a valid alternate project value and apply the
same Z0001 assertion, ensuring foreign-key errors cannot satisfy the test.
- Around line 35-46: Replace the fmt.Sprintf-based queries in the test with
static SQL statements targeting the volumes table for both the insert and count
assertion. Remove the quotedTable interpolation from these assertions; if
additional tables are later supported, use explicitly allowlisted complete query
strings.

In
`@fulfillment-service/internal/database/migrations/93_create_volumes_tables.up.sql`:
- Line 14: Rename the migration version used by the volume tables migration from
93 to an unused version, and update the corresponding migration filename and
identifiers in 93_create_volumes_tables_test.go, including all tool.Migrate(ctx,
93) calls, to keep the migration and tests synchronized.

In `@fulfillment-service/proto/private/osac/private/v1/volumes_service.proto`:
- Around line 87-95: Update PrivateVolumesServer.Update to reject any FieldMask
paths targeting VolumeSpec fields, including spec.size_gib, spec.storage_tier,
spec.access_mode, spec.cluster, spec.pvc_ref, and future spec fields, before
invoking the DAO save. Preserve updates to mutable fields and return the
service’s established validation error for invalid immutable-field changes; add
data-layer enforcement only if required by the existing architecture.

In `@osac-operator/api/v1alpha1/volume_types.go`:
- Around line 116-118: Update osac-operator/api/v1alpha1/volume_types.go:116-118
on the Conditions field with +listType=map, +listMapKey=type,
+patchStrategy=merge, and +patchMergeKey=type markers, and remove its protobuf
struct tag. Regenerate
osac-operator/config/crd/bases/osac.openshift.io_volumes.yaml:141-198 so
conditions uses a map list keyed by type, then re-sync
osac-operator/charts/operator-crds/templates/osac.openshift.io_volumes.yaml:143-200
with the regenerated CRD.
- Around line 32-36: Update the SizeGiB validation in the Volume API type to add
a kubebuilder Maximum constraint matching the largest volume supported by all
storage backends. Keep the existing Required, Minimum, and immutability
validations unchanged, and use an integer-safe bound to prevent oversized
requests from reaching vendor CSI CreateVolume.
- Around line 45-56: Replace the field-level XValidation rules on Cluster and
PVCRef with a spec-level transition validation rule using optionalOldSelf: true,
enforcing that once either optional field is set it cannot be changed or unset
while still allowing an initially absent value to be added. Apply the rule at
the containing spec type and preserve the existing field optionality and JSON
definitions.
🪄 Autofix

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: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 64accf26-f9e2-42f5-b90d-68426bfdff89

📥 Commits

Reviewing files that changed from the base of the PR and between 87ad589 and ef40810.

⛔ Files ignored due to path filters (8)
  • fulfillment-service/internal/api/osac/private/v1/event_type.pb.go is excluded by !**/*.pb.go
  • fulfillment-service/internal/api/osac/private/v1/event_type_protoopaque.pb.go is excluded by !**/*.pb.go
  • fulfillment-service/internal/api/osac/private/v1/volume_type.pb.go is excluded by !**/*.pb.go
  • fulfillment-service/internal/api/osac/private/v1/volume_type_protoopaque.pb.go is excluded by !**/*.pb.go
  • fulfillment-service/internal/api/osac/private/v1/volumes_service.pb.go is excluded by !**/*.pb.go
  • fulfillment-service/internal/api/osac/private/v1/volumes_service.pb.gw.go is excluded by !**/*.pb.gw.go
  • fulfillment-service/internal/api/osac/private/v1/volumes_service_grpc.pb.go is excluded by !**/*.pb.go
  • fulfillment-service/internal/api/osac/private/v1/volumes_service_protoopaque.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (16)
  • fulfillment-service/internal/cmd/service/start/grpcserver/start_grpc_server_cmd.go
  • fulfillment-service/internal/cmd/service/start/restgateway/start_rest_gateway_cmd.go
  • fulfillment-service/internal/database/migrations/93_create_volumes_tables.up.sql
  • fulfillment-service/internal/database/migrations/93_create_volumes_tables_test.go
  • fulfillment-service/internal/rendering/tables/osac.private.v1.Volume.yaml
  • fulfillment-service/internal/servers/private_volumes_server.go
  • fulfillment-service/internal/servers/private_volumes_server_test.go
  • fulfillment-service/proto/private/osac/private/v1/event_type.proto
  • fulfillment-service/proto/private/osac/private/v1/volume_type.proto
  • fulfillment-service/proto/private/osac/private/v1/volumes_service.proto
  • osac-operator/api/v1alpha1/groupversion_info.go
  • osac-operator/api/v1alpha1/volume_names.go
  • osac-operator/api/v1alpha1/volume_types.go
  • osac-operator/api/v1alpha1/zz_generated.deepcopy.go
  • osac-operator/charts/operator-crds/templates/osac.openshift.io_volumes.yaml
  • osac-operator/config/crd/bases/osac.openshift.io_volumes.yaml

Comment thread osac-operator/api/v1alpha1/volume_types.go
Comment thread osac-operator/api/v1alpha1/volume_types.go Outdated
Comment thread osac-operator/api/v1alpha1/volume_types.go Outdated
Volume CRD for the osac-operator, representing block storage provisioned
on vendor arrays through the storage control plane.

VolumeSpec (immutable after creation):
- storageTier: name of the StorageTier for backend/protocol resolution
- sizeGiB: requested capacity
- accessMode: Kubernetes access mode (ReadWriteOnce, ReadWriteMany)
- cluster: optional, cluster where the PVC exists
- pvcRef: optional PVC reference set by the CSI driver

VolumeStatus:
- phase: Progressing, Ready, Failed, Deleting
- conditions: VendorProvisioned (set True by Volume controller after
  vendor CSI CreateVolume succeeds)
- vendorVolumeID, backend, protocol: resolved by tier resolution
- pvcRef, pvRef: operator-confirmed PVC/PV on tenant cluster

Constants (volume_names.go): namespace (osac-volume), labels
(volume, volume-uuid), finalizers (volume, feedback, cleanup).

Scheme registration in groupversion_info.go. Print columns show Tier,
Size, Access, Cluster, Phase (default) and Backend, VendorID (wide).

Generated: CRD manifest, deepcopy, Helm chart CRD sync.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
- Remove spec.cluster from proto and CRD: cluster association will be
  tracked via status or a future attach/detach model, not as an immutable
  spec field. This keeps the volume representation consistent regardless
  of creation flow (PVC-driven vs standalone).

- Add list-map markers to CRD Conditions field (+listType=map,
  +listMapKey=type) so server-side apply merges conditions by type
  instead of overwriting the entire array.

- Assert SQLSTATE Z0001 in migration immutability tests to verify the
  check_immutable_columns trigger fires (not a foreign key error).

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Address reviewer feedback from Zoltan:

1. VolumeAccessMode enum (proto + CRD): access_mode is now a typed enum
   matching Kubernetes PersistentVolume access modes (ReadWriteOnce,
   ReadOnlyMany, ReadWriteMany, ReadWriteOncePod) instead of a raw string.

2. StorageProtocol reuse (proto + CRD): status.protocol now uses the
   existing StorageProtocol enum instead of a raw string. Moved
   StorageProtocol from storage_tier_type.proto to a new shared
   storage_common_type.proto to avoid a false dependency between Volume
   and StorageTier.

3. Create validation: added validateVolumeCreate method to the server,
   matching the pattern used by StorageBackends and StorageTiers. Validates
   metadata.name, spec.storage_tier, spec.size_gib, and spec.access_mode
   before persisting.

Tests: all 85 fulfillment-service suites pass, osac-operator lint 0 issues
and all tests pass.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
The fulfillment-service reconciler needs to track which hub cluster
hosts the Volume CR so the delete path can look up the correct hub
client. Every other hub-based resource (ComputeInstance, NATGateway,
Subnet, etc.) has this field for the same reason.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Move hub from field 8 to field 6 in VolumeStatus proto, grouping it
with the other system-resolved fields (vendor_volume_id, backend,
protocol) and before the reference fields (pvc_ref, pv_ref).

Add a spec-level CEL transition rule on VolumeSpec that prevents pvcRef
from being removed once set. The existing field-level rule (self ==
oldSelf) prevents value changes but is skipped when the field is absent.
The new rule (!has(oldSelf.pvcRef) || has(self.pvcRef)) blocks removal,
completing the immutability guarantee.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:00 PM UTC · Completed 1:17 PM UTC

Commit: 9de3972 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [authorization] fulfillment-service/internal/servers/private_volumes_server.go:133 — The Update method passes through to generic.Update without enforcing spec immutability. The proto documents VolumeSpec as “immutable after creation” and the CRD enforces this via XValidation rules (self == oldSelf), but the gRPC API path allows spec fields (storage_tier, size_gib, access_mode, pvc_ref) to be modified via Update with an appropriate update_mask. Compare with PrivateStorageTiersServer.Update which fetches the existing object and validates immutable fields before delegating. The PR description acknowledges this is deferred to the controller PR.
    Remediation: Add spec immutability validation in the Update method — fetch the existing volume, verify spec fields are unchanged, reject with InvalidArgument if modified.

  • [protobuf source compatibility] fulfillment-service/proto/private/osac/private/v1/storage_common_type.proto:18 — The StorageProtocol enum was moved from storage_tier_type.proto to the new storage_common_type.proto. The wire format is unchanged (same package, same field numbers), but this is a FILE-level breaking change under the buf.yaml breaking policy (breaking.use: [FILE]). The buf breaking check in CI will flag this. Downstream consumers (osac-operator, osac-metering) will need to regenerate protobuf output when they update their BSR module dependency.
    Remediation: Ensure the CI buf breaking check is configured to accept this move. Document that downstream consumers must run buf generate when bumping to the new BSR module version.

  • [design-direction] osac-operator/api/v1alpha1/volume_types.go — The CRD uses Phase values (Progressing/Ready/Failed/Deleting) while the proto uses a different state machine (CREATING/AVAILABLE/FAILED/DELETING/DELETED). The naming divergence (Ready vs. AVAILABLE, Progressing vs. CREATING) follows the established CRD-vs-proto convention, but the mapping should be documented when the feedback controller is implemented.

Low

  • [documentation accuracy] fulfillment-service/internal/database/migrations/95_create_volumes_tables.up.sql:62 — The SQL comment reads “Enforce immutability of id, tenant, and project columns” but the trigger enforces four columns: id, name, tenant, project. The test correctly exercises all four.
    Remediation: Fix the comment to include name.

  • [stale-resource-list] .claude/rules/architecture-patterns.md — The Resource Hierarchy section does not list Volume as a resource type.
    Remediation: Add a Storage Resources section listing Volume.

  • [stale-resource-list] osac-operator/AGENTS.md — The Resources Managed list does not include the new Volume CRD.
    Remediation: Add Volume (vol) to the Resources Managed list.

  • [stale-resource-list] README.md — The root README’s osac-operator description omits Volume from the CRD list (note: the list was already incomplete before this PR).
    Remediation: Add Volume to the CRD list.

  • [naming-convention] osac-operator/api/v1alpha1/volume_types.go:163 — Volume struct is missing the descriptive inline comments on metadata/spec/status fields that every other CRD type in the package includes.
    Remediation: Add standard field comments matching other CRDs.

  • [pattern-inconsistency] osac-operator/api/v1alpha1/volume_types.go:163 — Every other CRD type includes an Age printcolumn. The Volume type omits it.
    Remediation: Add +kubebuilder:printcolumn:name="Age",type=date,JSONPath='.metadata.creationTimestamp'.

  • [pattern-inconsistency] osac-operator/api/v1alpha1/volume_types.go:195 — Every other CRD type defines a GetName() helper method. The Volume type does not.
    Remediation: Add func (v *Volume) GetName() string { return v.ObjectMeta.Name }.

  • [authorization] fulfillment-service/internal/servers/private_volumes_server.go:109validateVolumeCreate validates that spec.storage_tier is non-empty but does not verify the referenced StorageTier exists in the database.
    Remediation: Consider adding a StorageTiersDAO dependency and validating the storage_tier reference.

  • [validation gap] fulfillment-service/proto/private/osac/private/v1/volume_type.proto:45 — The access_mode field uses defined_only = true which accepts VOLUME_ACCESS_MODE_UNSPECIFIED (0). The server’s validateVolumeCreate correctly catches this, so there is no runtime bug.

Previous run

Review

Findings

Medium

  • [pattern-inconsistency] osac-operator/api/v1alpha1/volume_names.go — Every existing *_names.go file in the operator lives in internal/controller/ (package controller) and uses unexported var declarations with fmt.Sprintf and the shared osacPrefix variable. This file is placed in api/v1alpha1/ and uses exported const declarations with hardcoded string literals, deviating from the established pattern.
    Remediation: Move volume_names.go to osac-operator/internal/controller/volume_names.go (package controller), use unexported var declarations with fmt.Sprintf and osacPrefix following existing names files. If the constants intentionally need to be exported for cross-package use, document that design departure.

Low

  • [test-adequacy] fulfillment-service/internal/database/migrations/95_create_volumes_tables_test.go:147 — The test "Enforces immutability of id, name, tenant, and project" verifies id, name, and tenant immutability but does not test the project column, despite the SQL trigger including project as immutable.

  • [input-validation] fulfillment-service/proto/private/osac/private/v1/volume_type.proto:99 — The size_gib field has a lower bound validation (int64.gt = 0) but no upper bound constraint. While this is a private/admin-only API, an extremely large value could cause issues in downstream storage provisioning.

  • [architecture-coherence] .claude/rules/architecture-patterns.md — Volume is a new tenant-scoped resource not yet included in the documented Resource Hierarchy. Best addressed when the resource is feature-complete (controller PR).

  • [protobuf-enum-relocation] fulfillment-service/proto/private/osac/private/v1/storage_common_type.proto:20StorageProtocol enum moved from storage_tier_type.proto to storage_common_type.proto. Wire-compatible but downstream consumers (osac-operator BSR v0.0.83, osac-metering BSR v0.0.84) will need to regenerate after the new BSR version is published.

  • [stale-doc] osac-operator/README.md:9 — CRD list does not include the new Volume CRD. Best updated when the Volume controller lands.

  • [stale-doc] osac-operator/AGENTS.md:7 — Resources Managed section omits the new Volume CRD.

  • [stale-doc] AGENTS.md:10 — osac-operator component description does not mention storage CRDs.


Labels: PR adds Volume resource to the storage control plane (proto, DB migration, CRD types)

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Aug 11, 2026
Add Entry("archived_volumes") to the migration DescribeTable to verify
the archived table is created and accepts inserts.

Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
Assisted-by: Cursor/Claude
Signed-off-by: akshaynadkarni <25892229+akshaynadkarni@users.noreply.github.com>
@rgolangh

Copy link
Copy Markdown
Contributor

/lgtm
/approve

@rgolangh

Copy link
Copy Markdown
Contributor

/lgtm

@akshaynadkarni

Copy link
Copy Markdown
Contributor Author

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

@openshift-ci

openshift-ci Bot commented Aug 11, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: akshaynadkarni, rgolangh, zszabo-rh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:24 PM UTC · Completed 4:41 PM UTC

Commit: 9d9e8b2 · View workflow run →

@akshaynadkarni

Copy link
Copy Markdown
Contributor Author

/lgtm

@openshift-ci

openshift-ci Bot commented Aug 11, 2026

Copy link
Copy Markdown

@akshaynadkarni: you cannot LGTM your own PR.

Details

In response to this:

/lgtm

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@wgordon17

Copy link
Copy Markdown
Contributor

/lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants