Skip to content

feat(rest-api): Tenant TargetedInstanceCreation capability implementation#2134

Open
hwadekar-nv wants to merge 29 commits into
NVIDIA:mainfrom
hwadekar-nv:feat/tenant-capabilities-update
Open

feat(rest-api): Tenant TargetedInstanceCreation capability implementation#2134
hwadekar-nv wants to merge 29 commits into
NVIDIA:mainfrom
hwadekar-nv:feat/tenant-capabilities-update

Conversation

@hwadekar-nv

@hwadekar-nv hwadekar-nv commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Description

Problem

Privileged tenant access (TargetedInstanceCreation) was stored on the global Tenant.config and surfaced as a single Tenant.capabilities.targetedInstanceCreation flag. That model is too coarse: the capability can differ by Provider and Site, and tenants may need per-site overrides. A tenant-wide flag also made it easy to over-grant access on list endpoints (e.g. machines/sites) when only some sites should be privileged.

What this PR does
Moves capability configuration and enforcement to the account/site model and makes authorization site-aware end to end.

Configuration model

  1. TenantAccount.config — provider-scoped defaults (targetedInstanceCreation, enableSshAccess)
  2. TenantSite.config — optional per-site override for targetedInstanceCreation
  3. TenantAccount PATCH siteCapabilities — Provider Admin API to set capability globally or for explicit site lists (global / limited scope), with server validation (exactly one global entry, no duplicate site IDs, etc.)
  4. Migration — backfills tenant_account.config from legacy tenant.config, then drops tenant.config
  5. Tenant.capabilities.targetedInstanceCreation — kept for compatibility but deprecated (still derived from account state)

TenantAccount API (siteCapabilities)

  1. POST /tenant/account — Provider Admin creates a Tenant Account invite (tenantOrg / tenantId). Capability configuration is not set at create time.
  2. PATCH /tenant/account/{accountId} — two mutually exclusive update paths:
    Provider Admin + siteCapabilities — replace capability configuration globally (scope: global) or for explicit sites (scope: limited + siteIds). Server validates: non-empty array, exactly one global entry, no duplicate siteIds, siteIds required for limited / omitted for global.
    Tenant Admin + tenantContactId — accept an Invited account (existing flow). Cannot be combined with siteCapabilities in the same request (400).
  3. GET /tenant/account/{accountId} — returns siteCapabilities on the TenantAccount response (one global entry from TenantAccount.config, plus limited entries for per-site overrides that differ from the global default).

Authorization / enforcement

  1. New helpers in common.go:
    TenantHasTargetedInstanceCreation(tenant, site?) — tenant-wide or effective per-site check (account default + TenantSite override)
    GetPrivilegedAccessSiteIDsForTenant — returns the exact set of privileged site IDs
  2. List and action handlers updated to use effective per-site access instead of tenant-wide expansion:
    Sites, Machines, Expected Machines, Instances, VPCs, SKUs, etc.
  3. TenantSite update validates mutually exclusive inputs before writing (no partial updates on bad requests)

API / docs

  1. OpenAPI updated for siteCapabilities schema and validation rules
  2. SDK models regenerated

Typical capability setup flow

  1. Provider Admin POSTs a Tenant Account invite.
  2. Tenant Admin PATCHes with tenantContactId to accept → account becomes Ready.
  3. Provider Admin PATCHes with siteCapabilities to enable/configure targetedInstanceCreation globally or per site.

Reviewer focus areas

  1. Effective capability resolution — TenantAccount.config + TenantSite.config override logic in common.go
  2. List filtering — privileged tenants are scoped to GetPrivilegedAccessSiteIDsForTenant, not all provider sites
  3. TenantAccount PATCH — siteCapabilities replace semantics and advisory-lock behavior
  4. Migration — backfill correctness for existing tenants with targetedInstanceCreation / enableSshAccess

Closes #2104

Type of Change

  • Add - New feature or capability

Related Issues (Optional)

#2104

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated

Additional Notes

@hwadekar-nv hwadekar-nv self-assigned this Jun 2, 2026
@hwadekar-nv
hwadekar-nv requested a review from a team as a code owner June 2, 2026 21:51
@hwadekar-nv
hwadekar-nv marked this pull request as draft June 2, 2026 21:51
@copy-pr-bot

copy-pr-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-06-02 21:53:17 UTC | Commit: 1feb71c

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

🔍 Container Scan Summary

No Grype artifacts were found to aggregate.

@hwadekar-nv hwadekar-nv changed the title feat: Tenant TargetedInstanceCreation capability implementation feat(rest-api): Tenant TargetedInstanceCreation capability implementation Jun 3, 2026
@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch from 2fff422 to 7d6bcc6 Compare June 3, 2026 22:10
@coderabbitai

coderabbitai Bot commented Jun 3, 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

This change moves TargetedInstanceCreation from tenant-level configuration to Ready tenant-account defaults with tenant-site overrides. It adds scoped capability resolution, site-capability APIs, authorization updates across handlers, database migrations, compatibility behavior, tests, and OpenAPI documentation.

Changes

Targeted instance creation capability

Layer / File(s) Summary
Capability storage and resolution
rest-api/db/pkg/db/model/*, rest-api/db/pkg/migrations/*, rest-api/api/pkg/api/handler/util/common/*
Tenant-account and tenant-site configuration become typed JSONB models; effective capability resolution supports provider and site scopes, overrides, and privileged-site expansion.
Tenant-account API and responses
rest-api/api/pkg/api/model/tenant*.go, rest-api/api/pkg/api/handler/tenantaccount.go, rest-api/api/pkg/api/handler/serviceaccount.go
Tenant-account responses expose siteCapabilities; PATCH requests validate and persist account defaults and provider-owned site overrides using transactional locking.
Authorization integration
rest-api/api/pkg/api/handler/{instance,machine,site,sku,vpc,expectedmachine}.go, rest-api/api/pkg/api/handler/*
Handlers defer capability checks until target sites or machines are known and apply site- or provider-scoped authorization results.
Migration and compatibility
rest-api/db/pkg/migrations/*, rest-api/openapi/*
Legacy tenant capability values are backfilled into Ready tenant accounts and tenant sites, while the legacy tenant field remains readable and is documented as deprecated.
Tests and fixtures
rest-api/api/pkg/api/handler/*_test.go, rest-api/api/pkg/api/model/*_test.go, rest-api/db/pkg/db/model/*_test.go
Tests now configure capabilities on Ready tenant accounts and tenant-site overrides and cover validation, persistence, authorization, migration, and response derivation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProviderAdmin
  participant UpdateTenantAccountHandler
  participant TenantAccountDAO
  participant TenantSiteDAO
  ProviderAdmin->>UpdateTenantAccountHandler: PATCH siteCapabilities
  UpdateTenantAccountHandler->>TenantAccountDAO: update account default in transaction
  UpdateTenantAccountHandler->>TenantSiteDAO: apply or clear site overrides
  UpdateTenantAccountHandler-->>ProviderAdmin: return tenant account siteCapabilities
Loading

Possibly related PRs

  • NVIDIA/infra-controller#3678 — Changes overlap in Expected Machine handler paths, although that PR addresses BMC IP clearing rather than capability authorization.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing Tenant TargetedInstanceCreation capability support.
Description check ✅ Passed The description is directly related to the PR and accurately describes the capability migration and API updates.
Linked Issues check ✅ Passed The changes address #2104 by moving TargetedInstanceCreation to tenant-account/site-scoped APIs and adding PATCH support.
Out of Scope Changes check ✅ Passed The modified handlers, models, migrations, docs, and tests all support the targetedInstanceCreation capability work.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch 2 times, most recently from ec337d8 to eeb42e0 Compare June 4, 2026 20:23
@hwadekar-nv

Copy link
Copy Markdown
Contributor Author

Will start working on this PR after 2.0. We have new strategies to allow tenants to update capabilities via TenantAccount and TenantSite across all Sites or specific Site.

@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch 2 times, most recently from 685f8f1 to c3402d9 Compare July 2, 2026 18:32
@hwadekar-nv hwadekar-nv added this to the v2.1 milestone Jul 2, 2026
@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch 2 times, most recently from 482fc88 to d20920e Compare July 7, 2026 21:31
@hwadekar-nv
hwadekar-nv marked this pull request as ready for review July 7, 2026 21:37
@hwadekar-nv

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch from d20920e to 3c8f601 Compare July 7, 2026 21:46

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rest-api/db/pkg/db/model/tenantaccount.go (1)

546-564: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make mixed TenantAccount updates atomic.

Update can run the scalar-column update and the config merge as separate statements. If a caller passes tx == nil with both normal fields and Config, the first update can commit before the config merge fails. Prefer building one UPDATE, or require/wrap mixed updates in cdb.WithTx.

🤖 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 `@rest-api/db/pkg/db/model/tenantaccount.go` around lines 546 - 564, The
TenantAccount update path in the update method currently splits scalar field
changes and Config merging into separate UPDATE statements, which can leave
mixed updates partially applied when tx is nil. Refactor the logic around
updatedFields/input.Config in TenantAccount.Update to perform a single atomic
update when both kinds of changes are present, or ensure mixed updates are
always executed inside cdb.WithTx by wrapping/requiring a transaction before
running db.GetIDB(...).NewUpdate().Exec.

Source: Path instructions

🧹 Nitpick comments (3)
rest-api/api/pkg/api/model/tenantaccountsitecapability.go (1)

199-206: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer a receiver method over a free function on the named type.

GlobalTargetedInstanceCreationFromRequest operates entirely on APITenantAccountSiteCapabilitiesUpdateRequest; expressing it as a method (e.g. caps.GlobalTargetedInstanceCreation()) keeps behavior colocated with the type and reads more naturally at the call site.

As per path instructions: "discourage scattered independent functions when a receiver method would make ownership and responsibilities clearer."

♻️ Proposed conversion to a receiver method
-func GlobalTargetedInstanceCreationFromRequest(caps APITenantAccountSiteCapabilitiesUpdateRequest) *bool {
-	for _, cap := range caps {
+func (caps APITenantAccountSiteCapabilitiesUpdateRequest) GlobalTargetedInstanceCreation() *bool {
+	for _, cap := range caps {
 		if cap.Scope == TenantAccountSiteCapabilityScopeGlobal {
 			return cutil.GetPtr(cap.TargetedInstanceCreation)
 		}
 	}
 	return nil
 }
🤖 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 `@rest-api/api/pkg/api/model/tenantaccountsitecapability.go` around lines 199 -
206, Convert GlobalTargetedInstanceCreationFromRequest into a receiver method on
APITenantAccountSiteCapabilitiesUpdateRequest so the behavior lives with the
type and can be called as caps.GlobalTargetedInstanceCreation(). Keep the same
logic that scans for TenantAccountSiteCapabilityScopeGlobal and returns the
targeted instance creation value, but move it onto the named type and update any
call sites accordingly.

Source: Path instructions

rest-api/db/pkg/db/model/tenantsite_test.go (2)

287-293: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use range-over-integer for this counting loop.

-	for i := 0; i < siteCount; i++ {
+	for i := range siteCount {

As per coding guidelines, “Counting loop → range-over-integer.” As per path instructions, prefer range-based iteration over C-style for loops.

🤖 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 `@rest-api/db/pkg/db/model/tenantsite_test.go` around lines 287 - 293, The
counting loop in the tenant site test should use range-over-integer instead of a
C-style for loop. Update the iteration in the site-building block within the
test that uses TestBuildSite and TestBuildTenantSite so it iterates with a
range-based integer loop over siteCount, while preserving the existing indexing
and even/odd behavior.

Sources: Coding guidelines, Path instructions


602-701: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test case for RemoveTargetedInstanceCreation.

The DAO now has a clear-override branch, but this table only verifies config merge. Add a case that starts with targetedInstanceCreation=true, updates with RemoveTargetedInstanceCreation: true, and asserts the pointer is cleared.

🤖 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 `@rest-api/db/pkg/db/model/tenantsite_test.go` around lines 602 - 701, Add a
missing Update test for the clear-override path in TenantSiteSQLDAO.Update: the
current TestTenantSiteSQLDAO_Update only covers config merge, so add a case that
seeds TenantSiteConfig.TargetedInstanceCreation as true, calls Update with
TenantSiteConfigUpdateInput.RemoveTargetedInstanceCreation set to true, and
asserts the resulting TenantSite.Config.TargetedInstanceCreation is cleared/nil.
Use the existing TenantSiteSQLDAO.Update, TenantSiteUpdateInput, and
TenantSiteConfigUpdateInput symbols to locate the right spot in the table-driven
test.

Source: Path instructions

🤖 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 `@rest-api/api/pkg/api/handler/machine.go`:
- Line 245: Update the privileged machine read authorization to use the
site-effective targeted-instance capability instead of the legacy tenant
flag/provider-account check. In the machine read paths around the
TenantHasTargetedInstanceCreation logic, switch single-machine reads to
EffectiveTargetedInstanceCreation(ctx, nil, ..., tenant, machine.SiteID), and
for list reads apply the same site-aware rule when siteId is present so
disabled-site machines are not returned in tenant-privileged results. Make sure
the behavior in the machine handler keeps honoring TenantAccount.config, Ready
status, and TenantSite.config overrides.
- Around line 762-768: The site-scoped capability check in IsProviderOrTenant is
being bypassed by the early requirePrivilegedTenant gate, which can reject
legacy TenantAccount tenants before machine.SiteID is evaluated. Update the
IsProviderOrTenant flow to defer the privileged-tenant rejection until after the
EffectiveTargetedInstanceCreation check runs, keeping the machine.SiteID-based
logic as the authoritative permission decision and removing the premature
pre-gate.

In `@rest-api/api/pkg/api/handler/util/common/common.go`:
- Around line 1467-1483: The privileged pre-check is still using the deprecated
tenant-level flag in TenantHasTargetedInstanceCreation, which can incorrectly
reject tenants enabled via the new TenantAccount.config path. Update the
requirePrivileged / requirePrivilegedTenant flow in common.go so non-site-scoped
privilege is resolved from the ready TenantAccount config, or remove this early
gate for site-aware callers and let EffectiveTargetedInstanceCreation be the
authoritative check. Keep the fix localized around
TenantHasTargetedInstanceCreation and the caller(s) that enforce the privileged
gate.

In `@rest-api/db/pkg/db/model/tenantsite.go`:
- Around line 314-334: The TenantSite update path currently applies Config
merging and RemoveTargetedInstanceCreation as separate updates, which can leave
partial state and makes conflicting input ambiguous. Update the logic in the
TenantSite model update flow to validate that both inputs are not used together,
then build a single NewUpdate/Exec path that applies either the JSONB merge or
the targetedInstanceCreation removal, not both. Use the existing update block
around input.Config and input.RemoveTargetedInstanceCreation to centralize the
decision and preserve one atomic update per request.

In
`@rest-api/db/pkg/migrations/20260701120000_tenant_account_site_capabilities.go`:
- Around line 26-33: The backfill in the migration only applies to Ready
tenant_account rows, so invited or pending accounts that later become Ready will
miss the legacy targetedInstanceCreation capability. Update the migration logic
in the tenant_account/tenant backfill to copy the capability for all matching
tenant_account rows tied to tenants with
tenant.config.targetedInstanceCreation=true, and if the status filter must
remain elsewhere, ensure the status transition path in tenant account handling
also propagates this config field when moving to Ready.

---

Outside diff comments:
In `@rest-api/db/pkg/db/model/tenantaccount.go`:
- Around line 546-564: The TenantAccount update path in the update method
currently splits scalar field changes and Config merging into separate UPDATE
statements, which can leave mixed updates partially applied when tx is nil.
Refactor the logic around updatedFields/input.Config in TenantAccount.Update to
perform a single atomic update when both kinds of changes are present, or ensure
mixed updates are always executed inside cdb.WithTx by wrapping/requiring a
transaction before running db.GetIDB(...).NewUpdate().Exec.

---

Nitpick comments:
In `@rest-api/api/pkg/api/model/tenantaccountsitecapability.go`:
- Around line 199-206: Convert GlobalTargetedInstanceCreationFromRequest into a
receiver method on APITenantAccountSiteCapabilitiesUpdateRequest so the behavior
lives with the type and can be called as caps.GlobalTargetedInstanceCreation().
Keep the same logic that scans for TenantAccountSiteCapabilityScopeGlobal and
returns the targeted instance creation value, but move it onto the named type
and update any call sites accordingly.

In `@rest-api/db/pkg/db/model/tenantsite_test.go`:
- Around line 287-293: The counting loop in the tenant site test should use
range-over-integer instead of a C-style for loop. Update the iteration in the
site-building block within the test that uses TestBuildSite and
TestBuildTenantSite so it iterates with a range-based integer loop over
siteCount, while preserving the existing indexing and even/odd behavior.
- Around line 602-701: Add a missing Update test for the clear-override path in
TenantSiteSQLDAO.Update: the current TestTenantSiteSQLDAO_Update only covers
config merge, so add a case that seeds TenantSiteConfig.TargetedInstanceCreation
as true, calls Update with
TenantSiteConfigUpdateInput.RemoveTargetedInstanceCreation set to true, and
asserts the resulting TenantSite.Config.TargetedInstanceCreation is cleared/nil.
Use the existing TenantSiteSQLDAO.Update, TenantSiteUpdateInput, and
TenantSiteConfigUpdateInput symbols to locate the right spot in the table-driven
test.
🪄 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: Enterprise

Run ID: aef13451-a675-454a-9c90-57bbe59434be

📥 Commits

Reviewing files that changed from the base of the PR and between 1c22f4d and d20920e.

⛔ Files ignored due to path filters (40)
  • rest-api/sdk/standard/api_tenant_account.go is excluded by !rest-api/sdk/standard/api_*.go
  • rest-api/sdk/standard/client.go is excluded by !rest-api/sdk/standard/client.go
  • rest-api/sdk/standard/model_batch_instance_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_interface.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_interface_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_machine.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_machine_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_site_capability.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_site_capability_scope.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_capabilities.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
📒 Files selected for processing (21)
  • rest-api/api/pkg/api/handler/instance.go
  • rest-api/api/pkg/api/handler/machine.go
  • rest-api/api/pkg/api/handler/serviceaccount.go
  • rest-api/api/pkg/api/handler/tenantaccount.go
  • rest-api/api/pkg/api/handler/util/common/common.go
  • rest-api/api/pkg/api/handler/util/common/common_test.go
  • rest-api/api/pkg/api/handler/vpc.go
  • rest-api/api/pkg/api/model/operatingsystem_test.go
  • rest-api/api/pkg/api/model/sshkeygroup_test.go
  • rest-api/api/pkg/api/model/tenant.go
  • rest-api/api/pkg/api/model/tenant_test.go
  • rest-api/api/pkg/api/model/tenantaccount.go
  • rest-api/api/pkg/api/model/tenantaccount_test.go
  • rest-api/api/pkg/api/model/tenantaccountsitecapability.go
  • rest-api/db/pkg/db/model/tenantaccount.go
  • rest-api/db/pkg/db/model/tenantsite.go
  • rest-api/db/pkg/db/model/tenantsite_test.go
  • rest-api/db/pkg/db/model/testing.go
  • rest-api/db/pkg/migrations/20230412224951_tenant_site.go
  • rest-api/db/pkg/migrations/20260701120000_tenant_account_site_capabilities.go
  • rest-api/openapi/spec.yaml

Comment thread rest-api/api/pkg/api/handler/machine.go Outdated
Comment thread rest-api/api/pkg/api/handler/machine.go Outdated
Comment thread rest-api/api/pkg/api/handler/util/common/common.go Outdated
Comment thread rest-api/db/pkg/db/model/tenantsite.go
Comment thread rest-api/db/pkg/migrations/20260701120000_tenant_account_site_capabilities.go Outdated
@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch from 4a12952 to b0ee8a6 Compare July 8, 2026 00:01

@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

🧹 Nitpick comments (2)
rest-api/db/pkg/db/model/tenantsite_test.go (1)

287-297: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer range-over-integer for this counting loop.

The index is used solely as a counter (i%2, Sprintf), so this is a textbook candidate for Go's range-over-integer form.

♻️ Suggested refactor
-	sites := []*Site{}
-	siteCount := 30
-	for i := 0; i < siteCount; i++ {
+	sites := []*Site{}
+	siteCount := 30
+	for i := range siteCount {

As per path instructions: "Counting loop → range-over-integer. When the bound is a count ... use for i := range n".

🤖 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 `@rest-api/db/pkg/db/model/tenantsite_test.go` around lines 287 - 297, The
counting loop in the tenant site test uses an index only as a counter for naming
and parity checks, so refactor the loop to use Go’s range-over-integer form
instead of a classic three-part loop. Update the loop in the test setup that
builds sites and calls TestBuildSite/TestBuildTenantSite so the iteration
variable still supports the Sprintf name generation and i%2 branch, but the loop
itself follows the preferred range-over-integer pattern.

Source: Path instructions

rest-api/api/pkg/api/handler/machine.go (1)

305-331: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Redundant per-site resolution creates an N+1 on the machine-list hot path.

EffectiveTargetedInstanceCreation internally re-fetches the Site by ID and re-queries Ready TenantAccounts per provider, yet this loop already holds each site from siteDAO.GetAll and the provider is fixed for the inner iteration. The cost is O(providers × sites) with three DB round-trips per site. Consider resolving the provider's Ready TenantAccount once outside the inner loop and evaluating the per-site TenantSite override directly against the already-loaded site.

🤖 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 `@rest-api/api/pkg/api/handler/machine.go` around lines 305 - 331, The machine
list path has an N+1 problem because the loop in the handler around
siteDAO.GetAll and common.EffectiveTargetedInstanceCreation re-fetches each Site
and re-queries TenantAccount data for every site/provider pair. Refactor this
block so the provider’s Ready TenantAccount is resolved once per provider
outside the inner site loop, then use the already-loaded site data to check the
per-site TenantSite override directly instead of calling
EffectiveTargetedInstanceCreation for every site. Keep the existing error
handling/logging structure in the same handler flow.
🤖 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 `@rest-api/api/pkg/api/handler/machine.go`:
- Around line 294-337: The machine list filtering in the tenant branch is using
provider IDs even though EffectiveTargetedInstanceCreation is evaluated per
site, which can widen results to disabled sites. Update the logic in machine.go
around the tenant/filterSite handling to collect and append enabled site IDs
instead of provider IDs, and apply them through MachineFilterInput.SiteIDs
rather than InfrastructureProviderIDs. Keep the existing
EffectiveTargetedInstanceCreation and SiteDAO.GetAll flow, but change the
aggregation variable and final filter assignment so the list stays scoped to
sites where targeted instance creation is enabled.

---

Nitpick comments:
In `@rest-api/api/pkg/api/handler/machine.go`:
- Around line 305-331: The machine list path has an N+1 problem because the loop
in the handler around siteDAO.GetAll and
common.EffectiveTargetedInstanceCreation re-fetches each Site and re-queries
TenantAccount data for every site/provider pair. Refactor this block so the
provider’s Ready TenantAccount is resolved once per provider outside the inner
site loop, then use the already-loaded site data to check the per-site
TenantSite override directly instead of calling
EffectiveTargetedInstanceCreation for every site. Keep the existing error
handling/logging structure in the same handler flow.

In `@rest-api/db/pkg/db/model/tenantsite_test.go`:
- Around line 287-297: The counting loop in the tenant site test uses an index
only as a counter for naming and parity checks, so refactor the loop to use Go’s
range-over-integer form instead of a classic three-part loop. Update the loop in
the test setup that builds sites and calls TestBuildSite/TestBuildTenantSite so
the iteration variable still supports the Sprintf name generation and i%2
branch, but the loop itself follows the preferred range-over-integer pattern.
🪄 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: Enterprise

Run ID: 8bd15369-c9f6-45e7-b4dd-b1d7c80569ca

📥 Commits

Reviewing files that changed from the base of the PR and between 3c8f601 and b0ee8a6.

⛔ Files ignored due to path filters (40)
  • rest-api/sdk/standard/api_tenant_account.go is excluded by !rest-api/sdk/standard/api_*.go
  • rest-api/sdk/standard/client.go is excluded by !rest-api/sdk/standard/client.go
  • rest-api/sdk/standard/model_batch_instance_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_interface.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_interface_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_machine.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_machine_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_site_capability.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_site_capability_scope.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_capabilities.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
📒 Files selected for processing (23)
  • rest-api/api/pkg/api/handler/instance.go
  • rest-api/api/pkg/api/handler/machine.go
  • rest-api/api/pkg/api/handler/machine_test.go
  • rest-api/api/pkg/api/handler/serviceaccount.go
  • rest-api/api/pkg/api/handler/tenantaccount.go
  • rest-api/api/pkg/api/handler/util/common/common.go
  • rest-api/api/pkg/api/handler/util/common/common_test.go
  • rest-api/api/pkg/api/handler/vpc.go
  • rest-api/api/pkg/api/model/operatingsystem_test.go
  • rest-api/api/pkg/api/model/sshkeygroup_test.go
  • rest-api/api/pkg/api/model/tenant.go
  • rest-api/api/pkg/api/model/tenant_test.go
  • rest-api/api/pkg/api/model/tenantaccount.go
  • rest-api/api/pkg/api/model/tenantaccount_test.go
  • rest-api/api/pkg/api/model/tenantaccountsitecapability.go
  • rest-api/db/pkg/db/model/tenantaccount.go
  • rest-api/db/pkg/db/model/tenantaccount_test.go
  • rest-api/db/pkg/db/model/tenantsite.go
  • rest-api/db/pkg/db/model/tenantsite_test.go
  • rest-api/db/pkg/db/model/testing.go
  • rest-api/db/pkg/migrations/20230412224951_tenant_site.go
  • rest-api/db/pkg/migrations/20260701120000_tenant_account_site_capabilities.go
  • rest-api/openapi/spec.yaml
✅ Files skipped from review due to trivial changes (1)
  • rest-api/api/pkg/api/model/sshkeygroup_test.go
🚧 Files skipped from review as they are similar to previous changes (14)
  • rest-api/db/pkg/migrations/20230412224951_tenant_site.go
  • rest-api/db/pkg/db/model/testing.go
  • rest-api/api/pkg/api/model/tenant_test.go
  • rest-api/api/pkg/api/model/operatingsystem_test.go
  • rest-api/openapi/spec.yaml
  • rest-api/api/pkg/api/model/tenantaccount_test.go
  • rest-api/api/pkg/api/handler/instance.go
  • rest-api/api/pkg/api/handler/vpc.go
  • rest-api/db/pkg/db/model/tenantaccount.go
  • rest-api/api/pkg/api/model/tenantaccount.go
  • rest-api/api/pkg/api/model/tenantaccountsitecapability.go
  • rest-api/api/pkg/api/model/tenant.go
  • rest-api/db/pkg/db/model/tenantsite.go
  • rest-api/api/pkg/api/handler/tenantaccount.go

Comment thread rest-api/api/pkg/api/handler/machine.go Outdated
@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch from fdc9a2d to ffd8c7b Compare July 8, 2026 16:38

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
rest-api/api/pkg/api/handler/tenantaccount.go (2)

397-464: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

GetAllTenantAccountHandler silently drops per-site capability overrides.

Every list-response APITenantAccount is built with tenantSites=nil (Line 447), while GetTenantAccountHandler (Line 585) and the new PUT response (Line 932) now fetch and pass the actual TenantSite slice. Since NewAPITenantAccount derives SiteCapabilities from tenantSites, the list endpoint will only ever report the global scope and silently omit any limited per-site overrides — producing an inconsistent contract between GET /tenant-account (list) and GET /tenant-account/{id} for the same brand-new field.

Consider batch-fetching TenantSite rows grouped by tenant ID (mirroring the existing allocation-count batching pattern already in this handler) so list responses stay consistent with the detail view.

🤖 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 `@rest-api/api/pkg/api/handler/tenantaccount.go` around lines 397 - 464,
GetAllTenantAccountHandler is building APITenantAccount list items with
tenantSites left nil, so NewAPITenantAccount cannot compute SiteCapabilities and
per-site limited overrides are lost. Update the list path in tenantaccount.go to
batch-load TenantSite rows for the tenants in tas, grouped by tenant ID similar
to the existing allocation-count fetch, and pass the matching tenantSites into
model.NewAPITenantAccount just like GetTenantAccountHandler and the PUT response
do.

907-937: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Hardcoded allocationCount: 0 in the siteCapabilities update response.

model.NewAPITenantAccount(ta, ssds, 0, tenantSites) always reports zero allocations, even though GetTenantAccountHandler computes the real value via aDAO.GetCount(...) for the exact same entity. A Provider Admin updating siteCapabilities on an active TenantAccount with existing allocations will get back a response claiming zero allocations.

🐛 Proposed fix
+	aDAO := cdbm.NewAllocationDAO(utah.dbSession)
+	total := 0
+	if ta.TenantID != nil {
+		cnt, cerr := aDAO.GetCount(ctx, nil, cdbm.AllocationFilterInput{
+			InfrastructureProviderIDs: []uuid.UUID{ta.InfrastructureProviderID},
+			TenantIDs:                 []uuid.UUID{*ta.TenantID},
+		})
+		if cerr != nil {
+			logger.Error().Err(cerr).Msg("error retrieving allocation count for Tenant Account from DB")
+			return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to retrieve Allocations to determine total allocation for tenant account", nil)
+		}
+		total = cnt
+	}
+
 	sdDAO := cdbm.NewStatusDetailDAO(utah.dbSession)
 	ssds, _, err := sdDAO.GetAll(ctx, nil, cdbm.StatusDetailFilterInput{EntityIDs: []string{ta.ID.String()}}, cdbp.PageInput{Limit: cutil.GetPtr(pagination.MaxPageSize)})
 	if err != nil {
 		logger.Error().Err(err).Msg("error retrieving Status Details for TenantAccount from DB")
 		return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to retrieve Status Details for TenantAccount", nil)
 	}
 
-	apiInstance := model.NewAPITenantAccount(ta, ssds, 0, tenantSites)
+	apiInstance := model.NewAPITenantAccount(ta, ssds, total, tenantSites)
🤖 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 `@rest-api/api/pkg/api/handler/tenantaccount.go` around lines 907 - 937, The
update response is hardcoding allocationCount to 0 in the call to
model.NewAPITenantAccount, so the returned TenantAccount can incorrectly show no
allocations. Reuse the same allocation-count logic already used in
GetTenantAccountHandler by fetching the real count for ta.ID before building the
response, then pass that value instead of 0 when constructing apiInstance.
rest-api/api/pkg/api/handler/expectedmachine.go (1)

351-365: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Mirror the TenantAccount fallback in the ExpectedMachine list filter.

GetAllExpectedMachineHandler only adds TenantSite.SiteID values to filterInput.SiteIDs. A privileged tenant that is authorized through a ready TenantAccount but has no explicit TenantSite row for a provider site will get an empty result set, and a siteId query for that site will be rejected, even though ValidateProviderOrTenantSiteAccess allows the same access path. Reuse the same access resolution here or extract a shared helper.

🤖 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 `@rest-api/api/pkg/api/handler/expectedmachine.go` around lines 351 - 365, The
ExpectedMachine list filter only uses TenantSite rows, so privileged tenants can
miss access granted through a ready TenantAccount. Update
GetAllExpectedMachineHandler to resolve site access the same way
ValidateProviderOrTenantSiteAccess does, or extract and reuse a shared helper,
so filterInput.SiteIDs includes both TenantSite.SiteID values and any provider
sites reachable via the TenantAccount fallback before applying the list filter.

Source: Path instructions

🧹 Nitpick comments (1)
rest-api/api/pkg/api/handler/tenantaccount.go (1)

785-932: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy lift

Add handler-level test coverage for the new provider siteCapabilities flow.

This introduces a non-trivial, security-sensitive authorization path (advisory-locked transaction, global vs. limited scope resolution, stale-override cleanup, cross-provider site scoping) with no accompanying tenantaccount_test.go changes in this layer. Given the privilege-granting nature of this endpoint, targeted tests (ownership rejection, stale-override cleanup, limited-site-not-owned-by-provider rejection) would materially reduce regression risk.

Based on path instructions: "Review Go code for correctness, clean control flow, error handling, context propagation, test coverage, performance, and cohesive organization..."

🤖 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 `@rest-api/api/pkg/api/handler/tenantaccount.go` around lines 785 - 932, Add
handler-level tests for handleProviderSiteCapabilitiesUpdate in tenantaccount.go
to cover the new provider siteCapabilities flow. Exercise the security-sensitive
branches by verifying ownership/provider rejection, limited-site validation when
a Site is not owned by the Tenant Account Infrastructure Provider, and stale
TenantSite override cleanup when a site is removed from the limited set. Use the
existing UpdateTenantAccountHandler, TenantAccountDAO/TenantSiteDAO behavior,
and the advisory-locked transaction path to locate the right handler logic.

Source: Path instructions

🤖 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.

Outside diff comments:
In `@rest-api/api/pkg/api/handler/expectedmachine.go`:
- Around line 351-365: The ExpectedMachine list filter only uses TenantSite
rows, so privileged tenants can miss access granted through a ready
TenantAccount. Update GetAllExpectedMachineHandler to resolve site access the
same way ValidateProviderOrTenantSiteAccess does, or extract and reuse a shared
helper, so filterInput.SiteIDs includes both TenantSite.SiteID values and any
provider sites reachable via the TenantAccount fallback before applying the list
filter.

In `@rest-api/api/pkg/api/handler/tenantaccount.go`:
- Around line 397-464: GetAllTenantAccountHandler is building APITenantAccount
list items with tenantSites left nil, so NewAPITenantAccount cannot compute
SiteCapabilities and per-site limited overrides are lost. Update the list path
in tenantaccount.go to batch-load TenantSite rows for the tenants in tas,
grouped by tenant ID similar to the existing allocation-count fetch, and pass
the matching tenantSites into model.NewAPITenantAccount just like
GetTenantAccountHandler and the PUT response do.
- Around line 907-937: The update response is hardcoding allocationCount to 0 in
the call to model.NewAPITenantAccount, so the returned TenantAccount can
incorrectly show no allocations. Reuse the same allocation-count logic already
used in GetTenantAccountHandler by fetching the real count for ta.ID before
building the response, then pass that value instead of 0 when constructing
apiInstance.

---

Nitpick comments:
In `@rest-api/api/pkg/api/handler/tenantaccount.go`:
- Around line 785-932: Add handler-level tests for
handleProviderSiteCapabilitiesUpdate in tenantaccount.go to cover the new
provider siteCapabilities flow. Exercise the security-sensitive branches by
verifying ownership/provider rejection, limited-site validation when a Site is
not owned by the Tenant Account Infrastructure Provider, and stale TenantSite
override cleanup when a site is removed from the limited set. Use the existing
UpdateTenantAccountHandler, TenantAccountDAO/TenantSiteDAO behavior, and the
advisory-locked transaction path to locate the right handler logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 337a24c6-0bfa-4a62-ab56-b6e48d7222c7

📥 Commits

Reviewing files that changed from the base of the PR and between b0ee8a6 and ffd8c7b.

⛔ Files ignored due to path filters (40)
  • rest-api/sdk/standard/api_tenant_account.go is excluded by !rest-api/sdk/standard/api_*.go
  • rest-api/sdk/standard/client.go is excluded by !rest-api/sdk/standard/client.go
  • rest-api/sdk/standard/model_batch_instance_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_machine_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_power_shelf_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_rack_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_expected_switch_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_infini_band_partition_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_type_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_instance_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_interface.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_interface_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_machine.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_machine_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_network_security_group_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_site_capability.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_site_capability_scope.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_account_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_tenant_capabilities.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc_create_request.go is excluded by !rest-api/sdk/standard/model_*.go
  • rest-api/sdk/standard/model_vpc_update_request.go is excluded by !rest-api/sdk/standard/model_*.go
📒 Files selected for processing (31)
  • rest-api/api/pkg/api/handler/dpureprovision_test.go
  • rest-api/api/pkg/api/handler/expectedmachine.go
  • rest-api/api/pkg/api/handler/expectedmachine_test.go
  • rest-api/api/pkg/api/handler/instance.go
  • rest-api/api/pkg/api/handler/instance_test.go
  • rest-api/api/pkg/api/handler/machine.go
  • rest-api/api/pkg/api/handler/machine_test.go
  • rest-api/api/pkg/api/handler/machinehealth_test.go
  • rest-api/api/pkg/api/handler/serviceaccount.go
  • rest-api/api/pkg/api/handler/sku_test.go
  • rest-api/api/pkg/api/handler/tenantaccount.go
  • rest-api/api/pkg/api/handler/util/common/common.go
  • rest-api/api/pkg/api/handler/util/common/common_test.go
  • rest-api/api/pkg/api/handler/util/common/testing.go
  • rest-api/api/pkg/api/handler/vpc.go
  • rest-api/api/pkg/api/handler/vpc_test.go
  • rest-api/api/pkg/api/model/operatingsystem_test.go
  • rest-api/api/pkg/api/model/sshkeygroup_test.go
  • rest-api/api/pkg/api/model/tenant.go
  • rest-api/api/pkg/api/model/tenant_test.go
  • rest-api/api/pkg/api/model/tenantaccount.go
  • rest-api/api/pkg/api/model/tenantaccount_test.go
  • rest-api/api/pkg/api/model/tenantaccountsitecapability.go
  • rest-api/db/pkg/db/model/tenantaccount.go
  • rest-api/db/pkg/db/model/tenantaccount_test.go
  • rest-api/db/pkg/db/model/tenantsite.go
  • rest-api/db/pkg/db/model/tenantsite_test.go
  • rest-api/db/pkg/db/model/testing.go
  • rest-api/db/pkg/migrations/20230412224951_tenant_site.go
  • rest-api/db/pkg/migrations/20260701120000_tenant_account_site_capabilities.go
  • rest-api/openapi/spec.yaml
✅ Files skipped from review due to trivial changes (2)
  • rest-api/api/pkg/api/model/sshkeygroup_test.go
  • rest-api/db/pkg/migrations/20230412224951_tenant_site.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • rest-api/api/pkg/api/model/tenantaccount_test.go
  • rest-api/api/pkg/api/model/operatingsystem_test.go
  • rest-api/api/pkg/api/model/tenant_test.go
  • rest-api/db/pkg/migrations/20260701120000_tenant_account_site_capabilities.go
  • rest-api/db/pkg/db/model/testing.go
  • rest-api/openapi/spec.yaml
  • rest-api/api/pkg/api/handler/vpc.go
  • rest-api/api/pkg/api/handler/instance.go
  • rest-api/api/pkg/api/handler/machine_test.go
  • rest-api/api/pkg/api/model/tenantaccountsitecapability.go
  • rest-api/api/pkg/api/handler/util/common/common.go
  • rest-api/api/pkg/api/handler/util/common/common_test.go
  • rest-api/api/pkg/api/model/tenant.go
  • rest-api/api/pkg/api/handler/serviceaccount.go
  • rest-api/db/pkg/db/model/tenantaccount_test.go
  • rest-api/db/pkg/db/model/tenantsite.go
  • rest-api/api/pkg/api/handler/machine.go
  • rest-api/api/pkg/api/model/tenantaccount.go
  • rest-api/db/pkg/db/model/tenantaccount.go
  • rest-api/db/pkg/db/model/tenantsite_test.go

@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch from 1375da6 to 04ce4d9 Compare July 8, 2026 17:09
@hwadekar-nv

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

hwadekar-nv and others added 29 commits July 21, 2026 19:35
Move privileged tenant capability configuration to TenantAccount.config and
TenantSite.config, expose it on TenantAccount GET/PATCH, and enforce effective
site-scoped checks on instance, machine, and VPC actions while deprecating the
legacy Tenant.capabilities field.
… responses, and require explicit siteCapabilities updates
…sence, invite response overrides, and capability auth cleanup
@hwadekar-nv
hwadekar-nv force-pushed the feat/tenant-capabilities-update branch from 50e13e0 to 7ee3450 Compare July 22, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: REST API should expose targetedInstanceCreation tenant capability toggle

2 participants