Skip to content

[AUT-13970] Keep phone_provider_config through a tenant pull/push - #51

Merged
jdabrowski merged 4 commits into
masterfrom
feature/aut-13970-cac-phone-provider-config
Aug 31, 2026
Merged

[AUT-13970] Keep phone_provider_config through a tenant pull/push#51
jdabrowski merged 4 commits into
masterfrom
feature/aut-13970-cac-phone-provider-config

Conversation

@jdabrowski

@jdabrowski jdabrowski commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Jira task

AUT-13970

Important

Do not merge before ciam-client-go#75. go.mod currently pins that PR's branch commit (1f193808) so this builds and tests green today; it needs re-pinning to a master pseudo-version once #75 lands. #75 is itself gated on a Customer Success sign-off.

Release Notes Description (public)

Tenant phone provider configuration can now be managed as code. cac pull writes it to phone_provider_config.yaml and cac push sends it back. Previously it was dropped on pull and could not be pushed at all.

SMS and voice delivery — including Twilio credentials and sender ID — is configured through the tenant's phone provider configuration. It is no longer driven by the provider field on an SMS or voice MFA method; that field is deprecated and no longer selects a messaging provider.

If you use --filter, add phone_provider_config to the list. --filter names what to include, so phone provider configuration is only sent when you ask for it:

cac push --tenant --method patch \
  --filter mfa_methods --filter pools --filter schemas \
  --filter phone_provider_config

Runs without --filter include it automatically.

Implementation details (internal)

Problem. TenantStorage never handled phone_provider_config. storeTenant serializes the tenant root through smodels.Tenant to strip sub-resources that live in their own files, and that struct — the Tenant API resource — has no such field, because server-side a phone provider configuration is a separate entity, not a tenant attribute. Nothing else picked it up either, so it was dropped on pull and could never be pushed back. This is why affected repositories contain no phone provider configuration at all, and it's the client-side half of the AUT-13968 incident.

Solution. Treat it as what it is — a singular sub-resource — and give it its own file, exactly as server storage already does for claims, consent, ciba, theme_binding and friends:

  • writeFile(model.PhoneProviderConfig, path/phone_provider_config) on the way out
  • readFileToMap(tenant, "phone_provider_config", ...) on the way back

storeTenant and tenant.yaml are untouched.

An earlier revision of this PR instead widened the model storeTenant serializes into. That was wrong: utils.TenantRootKeys is derived from the same type, deliberately, so that root-level keys stay in sync without a hand-maintained list. Widening one without the other wrote phone_provider_config into tenant.yaml while leaving it out of the root key set, so push --filter root silently dropped it. Keeping it a sub-resource avoids the coupling entirely.

Filter behaviour now matches mfa_methods:

--filter root                  -> [name]                    (correctly excludes it)
--filter phone_provider_config -> [phone_provider_config]   (targetable)
--filter mfa_methods           -> [mfa_methods]
no filter                      -> everything

Also bumps acp-client-go to the AUT-13969 spec sync so TreePhoneProviderConfig carries mode. Without it the config would round-trip mode-less, which is the shape that caused the original wipe.

Tests.

  • TestTenantStorage/phone_provider_config — asserts the config lands in phone_provider_config.yaml and tenant.yaml stays clean
  • TestTenantStoragePhoneProviderConfigRoundTrip — Write → Read → model, asserting mode and credentials survive

Both falsification-checked: dropping the writeFile call fails the round-trip with "phone_provider_config did not survive the round trip", and passes again when restored.

Two golden fixtures are updated for fields the client bump adds (require_user_interaction_before_prompt, enforce_application_membership, skip_dbfp). Full suite green with no replace directive.

Note for reviewers: a cac pull after this change adds a new phone_provider_config.yaml to repositories whose tenant has one. Credentials land in that file rather than in tenant.yaml.

Out of scope, but noted: the same gap also drops tenant-level features and translations, both of which are maps and would want the pools/mfa_methods directory treatment. Left as-is deliberately.


Reference

Twilio Enum Drift — the breaking-change analysis behind the client bump this PR depends on, including why the twilio provider value affects every migrated tenant rather than only stale checkouts. Access-controlled; ask if you need it opened up.

storeTenant filters the tenant root through smodels.Tenant to drop the collections
written to their own files. That struct predates phone_provider_config, so the field
was discarded on pull and could never be pushed back — which is why affected repos
have no phone provider configuration on disk at all.

Bumps acp-client-go to the AUT-13969 sync so the config carries `mode`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZykgo2CbxHjvnBzfWQxrL

Copilot AI 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.

Pull request overview

This PR updates tenant config-as-code persistence so phone_provider_config is no longer dropped when writing tenant.yaml, enabling it to survive a pull/push round trip.

Changes:

  • Introduces a tenantFile wrapper type to include phone_provider_config while still stripping sub-resources stored in separate files.
  • Adds/extends tests to validate phone_provider_config serialization and end-to-end round-trip preservation.
  • Bumps github.com/cloudentity/acp-client-go to a commit pseudo-version and updates golden YAML fixtures for newly surfaced fields.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/cac/storage/tenant_storage.go Writes tenant.yaml via a new wrapper type to preserve phone_provider_config.
internal/cac/storage/tenant_storage_test.go Adds fixture updates and new tests covering phone_provider_config persistence/round-trip.
internal/cac/storage/server_storage_test.go Updates golden YAML expectations for new fields from the client bump.
go.mod Pins acp-client-go to a specific commit pseudo-version required by upstream work.
go.sum Updates checksums for the new acp-client-go pseudo-version.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/cac/storage/tenant_storage.go Outdated
Comment thread internal/cac/storage/tenant_storage_test.go
Comment thread go.mod Outdated
Follows the pattern server storage already uses for singular sub-resources
(claims, consent, ciba, theme_binding): writeFile on the way out, readFileToMap
on the way back.

Replaces the earlier approach of widening the tenant.yaml model. That one broke
the invariant behind utils.TenantRootKeys, which is derived from the same type
storeTenant serializes into — phone_provider_config was written to tenant.yaml
but missing from the root key set, so `push --filter root` silently dropped it.
storeTenant is now untouched and the invariant holds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZykgo2CbxHjvnBzfWQxrL

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

go.mod:7

  • The explicit merge prerequisite is still unmet: this pseudo-version points to ciam-client-go#75's head commit, and that PR is currently open, draft, and blocked rather than merged to master. Re-pin this dependency to the resulting master pseudo-version after #75 lands; the current pin should not be merged.
	github.com/cloudentity/acp-client-go v0.0.0-20260820095634-1f1938087bcf

Comment thread go.mod Outdated
…trip test

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZykgo2CbxHjvnBzfWQxrL
@jdabrowski
jdabrowski marked this pull request as ready for review August 21, 2026 14:33
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrGXNzbqi2CPHE4nWHri7N

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

Auto-approve: assignee approved, Copilot reviewed, and no unresolved comments.

@jdabrowski
jdabrowski merged commit dff7d43 into master Aug 31, 2026
7 checks passed
@jdabrowski
jdabrowski deleted the feature/aut-13970-cac-phone-provider-config branch August 31, 2026 08:55
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.

4 participants