account

package
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 16, 2026 License: MIT Imports: 17 Imported by: 0

README

Account

Parity grade: A · SDK aws-sdk-go-v2/service/account@v1.35.4 · last audited 2026-08-10 (fca4a71a1)

Coverage

Metric Value
Operations audited 16 (16 ok)
Feature families 1 (1 ok)
Known gaps 5
Deferred items 1
Resource leaks clean
Known gaps
  • AccountId targeting of org member accounts is not modeled: GetAlternateContact/PutAlternateContact/DeleteAlternateContact/GetContactInformation/PutContactInformation/ListRegions/GetRegionOptStatus/EnableRegion/DisableRegion/GetAccountInformation/PutAccountName/GetPrimaryEmailUpdateStatus/GetGovCloudAccountInformation accept an optional AccountId/StandardAccountId (as AWS's wire contract requires) but operate on the single InMemoryBackend regardless of its value -- there is no per-member-account backend. GetPrimaryEmail/StartPrimaryEmailUpdate/AcceptPrimaryEmailUpdate validate AccountId is present (matching AWS's required-field contract) but likewise don't scope by it. Consistent with this service having always been a single-account backend; true multi-account modeling is a larger cross-service (Organizations-integration) project. GetGovCloudAccountInformation's always-ResourceNotFoundException behavior is a direct consequence: services/organizations already models a GovCloudAccountID linked at CreateGovCloudAccount time, but wiring account<->organizations the way grafana<->networkmanager already cross-link would require touching cli.go, out of this pass's scope. Re-verified 2026-08-10: this is NOT a silent-drop bug -- handler.go decodes AccountId/StandardAccountId into every request struct (e.g. handleGetContactInformation's req.AccountID, handleGetGovCloudAccountInformation's req.StandardAccountID) and enforces it as required exactly where validators.go's validateOpGetPrimaryEmailInput/validateOpStartPrimaryEmailUpdateInput/validateOpAcceptPrimaryEmailUpdateInput require it (GetPrimaryEmail/StartPrimaryEmailUpdate/AcceptPrimaryEmailUpdate only) -- the field is read and validated, just not used for routing. Genuinely blocked on a multi-account backend model (per-member-account state), not a lookup gopherstack already has the data for; services/organizations models Email per member account but wiring account<->organizations would mean editing cli.go, excluded from this pass.
  • EnableRegion/DisableRegion transition directly to the terminal state (ENABLED/DISABLED) instead of an async ENABLING/DISABLING window that a client would poll GetRegionOptStatus to observe. Real AWS takes minutes-to-hours; gopherstack completes immediately. This also means the documented ConflictException ("enable while DISABLING") can never actually fire here -- the window doesn't exist to race into. Not fixed: adding real async state to a Snapshot/Restore-backed backend risks non-deterministic tests and races under -race for a benefit (exercising a transient status) most callers/waiters don't depend on. Revisit if a bd issue specifically needs the transient states simulated. Re-verified 2026-08-10: this is a legitimate simplification, not a wire gap -- RegionOptStatusEnabling/RegionOptStatusDisabling ARE present in gopherstack's own enum (regions.go) and match the pinned SDK's types.RegionOptStatus.Values() (types/enums.go:110-117) exactly; nothing was missing from the source. No response field contradicts the simplification either: EnableRegionOutput/DisableRegionOutput (api_op_EnableRegion.go/api_op_DisableRegion.go) carry no fields at all besides ResultMetadata, and GetRegionOptStatusOutput (api_op_GetRegionOptStatus.go:62-75) is just {RegionName, RegionOptStatus} with no PendingChange/ETA field a caller could catch out of sync.
  • AcceptPrimaryEmailUpdate's real AcceptPrimaryEmailUpdateOutput reports Status ACCEPTED immediately, then asynchronously transitions to COMPLETED once the change actually propagates. This simulator does not model that async completion tail -- ACCEPTED is the terminal status GetPrimaryEmailUpdateStatus reports here, matching the EnableRegion/DisableRegion async-window gap above. PrimaryEmailUpdateStatusCompleted/Failed are modeled (matching the real enum) but never produced.
  • AccessDeniedException/TooManyRequestsException are wired into writeBackendError's classification table (so a backend error carrying that AWS exception name in its message would map to the correct HTTP status/code) but nothing in this backend's logic currently generates either -- there is no auth/permission model or throttle simulation in this service. Dead-but-correct code path; not a bug, just unexercised. ResourceUnavailableException (GetGovCloudAccountInformation's modeled error set) is the same: wired to 424, never produced. Re-verified 2026-08-10: this is legitimate and repo-consistent -- gopherstack has no per-request IAM policy evaluation or request-rate throttling in this service (nor is one specific to Account Management alone), so there is no real signal to trigger AccessDenied/TooManyRequests from. Not fabricating a synthetic rate-limit/permission model to force these to fire.
  • ConflictException's documented 'email address already in use' trigger is now simulated for the case this single-account backend can actually detect: StartPrimaryEmailUpdate rejects a target PrimaryEmail equal to the account's own current primaryEmail (2026-08-10 fix). The genuinely cross-account collision (targeting a different AWS account's email) remains unmodeled -- consistent with the AccountId/single-backend gap above: there is no second account's email to compare against. AcceptPrimaryEmailUpdate also models ConflictException (deserializers.go's awsRestjson1_deserializeOpErrorAcceptPrimaryEmailUpdate) but has no independent trigger to simulate: any self-collision is already caught at StartPrimaryEmailUpdate time, before a pending update (and its OTP) would exist to Accept.
Deferred
  • none (every routed op audited this pass)

More

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNilAppContext = errors.New("account: nil app context")

ErrNilAppContext is returned when Init is called with a nil AppContext.

Functions

This section is empty.

Types

type AlternateContact

type AlternateContact struct {
	AlternateContactType ContactType `json:"AlternateContactType"`
	EmailAddress         string      `json:"EmailAddress,omitempty"`
	Name                 string      `json:"Name,omitempty"`
	PhoneNumber          string      `json:"PhoneNumber,omitempty"`
	Title                string      `json:"Title,omitempty"`
}

AlternateContact holds alternate contact information.

type ContactInformation

type ContactInformation struct {
	AddressLine1     string `json:"AddressLine1"`
	AddressLine2     string `json:"AddressLine2,omitempty"`
	AddressLine3     string `json:"AddressLine3,omitempty"`
	City             string `json:"City"`
	CompanyName      string `json:"CompanyName,omitempty"`
	CountryCode      string `json:"CountryCode"`
	DistrictOrCounty string `json:"DistrictOrCounty,omitempty"`
	FullName         string `json:"FullName"`
	PhoneNumber      string `json:"PhoneNumber"`
	PostalCode       string `json:"PostalCode"`
	StateOrRegion    string `json:"StateOrRegion,omitempty"`
	WebsiteURL       string `json:"WebsiteUrl,omitempty"`
}

ContactInformation holds primary contact information for the account.

type ContactType

type ContactType string

ContactType represents the type of alternate contact.

const (
	ContactTypeBilling    ContactType = "BILLING"
	ContactTypeOperations ContactType = "OPERATIONS"
	ContactTypeSecurity   ContactType = "SECURITY"
)

type Handler

type Handler struct {
	Backend StorageBackend
}

Handler implements service.Registerable for the AWS Account Management API.

func NewHandler

func NewHandler(b StorageBackend) *Handler

NewHandler constructs a Handler backed by the given StorageBackend.

func (*Handler) ExtractOperation

func (h *Handler) ExtractOperation(c *echo.Context) string

ExtractOperation returns the operation name for logging/telemetry.

func (*Handler) ExtractResource

func (h *Handler) ExtractResource(c *echo.Context) string

ExtractResource returns a resource identifier for logging.

func (*Handler) GetSupportedOperations

func (h *Handler) GetSupportedOperations() []string

GetSupportedOperations lists the operations the handler implements.

func (*Handler) Handler

func (h *Handler) Handler() echo.HandlerFunc

Handler returns the echo handler function.

func (*Handler) MatchPriority

func (h *Handler) MatchPriority() int

MatchPriority returns the routing priority.

func (*Handler) Name

func (h *Handler) Name() string

Name returns the service name.

func (*Handler) Reset

func (h *Handler) Reset()

Reset delegates to the backend.

func (*Handler) Restore

func (h *Handler) Restore(ctx context.Context, data []byte) error

Restore implements persistence.Persistable by delegating to the backend.

func (*Handler) RouteMatcher

func (h *Handler) RouteMatcher() service.Matcher

RouteMatcher identifies account service requests by inspecting the SigV4 service name from the Authorization header and matching one of the fixed operation paths. Every operation is a POST -- Account Management has no GET/PUT/DELETE operations.

func (*Handler) Snapshot

func (h *Handler) Snapshot(ctx context.Context) []byte

Snapshot implements persistence.Persistable by delegating to the backend. Handler previously had no Snapshot/Restore of its own -- and neither did InMemoryBackend -- so a persistence manager that type-asserts the registered service.Registerable (i.e. the Handler) for a Snapshot/Restore pair never picked Account up at all: dead wiring, with no persistence underneath it either. This delegation (matching the cleanrooms/codecommit pattern) is what wires Account into persistence for the first time.

type InMemoryBackend

type InMemoryBackend struct {
	// contains filtered or unexported fields
}

InMemoryBackend is an in-memory implementation of StorageBackend.

func NewInMemoryBackend

func NewInMemoryBackend(accountID, region string) *InMemoryBackend

NewInMemoryBackend creates a new in-memory backend for the account service.

func (*InMemoryBackend) AcceptPrimaryEmailUpdate

func (b *InMemoryBackend) AcceptPrimaryEmailUpdate(otp, email string) error

AcceptPrimaryEmailUpdate confirms a pending email change using the OTP. Real AWS's AcceptPrimaryEmailUpdateOutput reports Status ACCEPTED immediately, then asynchronously transitions to COMPLETED once the change propagates; like EnableRegion/DisableRegion (see PARITY.md gaps), this simulator does not model that async completion tail -- ACCEPTED is the terminal status GetPrimaryEmailUpdateStatus reports here.

func (*InMemoryBackend) DeleteAlternateContact

func (b *InMemoryBackend) DeleteAlternateContact(ct ContactType) error

DeleteAlternateContact removes an alternate contact by type.

func (*InMemoryBackend) DisableRegion

func (b *InMemoryBackend) DisableRegion(regionName string) error

DisableRegion transitions an opt-in region from ENABLED to DISABLED. ENABLED_BY_DEFAULT regions return a ValidationException per AWS semantics.

func (*InMemoryBackend) EnableRegion

func (b *InMemoryBackend) EnableRegion(regionName string) error

EnableRegion transitions an opt-in region from DISABLED to ENABLED. ENABLED_BY_DEFAULT regions return a ValidationException per AWS semantics.

func (*InMemoryBackend) GetAccountInformation

func (b *InMemoryBackend) GetAccountInformation() (*Info, error)

GetAccountInformation returns the account's ID, display name, creation date, and lifecycle state. AccountState is always ACTIVE: this service has no operation that transitions it (account closure belongs to AWS Organizations -- see services/organizations CloseAccount).

func (*InMemoryBackend) GetAlternateContact

func (b *InMemoryBackend) GetAlternateContact(ct ContactType) (*AlternateContact, error)

GetAlternateContact retrieves an alternate contact by type.

func (*InMemoryBackend) GetContactInformation

func (b *InMemoryBackend) GetContactInformation() (*ContactInformation, error)

GetContactInformation retrieves primary contact information.

func (*InMemoryBackend) GetGovCloudAccountInformation added in v1.3.1

func (b *InMemoryBackend) GetGovCloudAccountInformation() (string, State, error)

GetGovCloudAccountInformation returns the GovCloud account linked to this account. This backend models a single, standalone (non-organization-member) account -- see the AccountId-targeting gap in PARITY.md -- so no account it simulates ever has a linked GovCloud pair; matches real AWS's documented ResourceNotFoundException for that case.

func (*InMemoryBackend) GetPrimaryEmail

func (b *InMemoryBackend) GetPrimaryEmail() string

GetPrimaryEmail returns the current primary email address.

func (*InMemoryBackend) GetPrimaryEmailUpdateStatus added in v1.3.1

func (b *InMemoryBackend) GetPrimaryEmailUpdateStatus() (PrimaryEmailUpdateStatus, time.Time, error)

GetPrimaryEmailUpdateStatus returns the status of the most recent primary email update request and when it last changed.

func (*InMemoryBackend) GetRegionOptStatus

func (b *InMemoryBackend) GetRegionOptStatus(regionName string) (RegionOptStatus, error)

GetRegionOptStatus returns the current opt-in status for a single region.

func (*InMemoryBackend) ListRegions

func (b *InMemoryBackend) ListRegions(
	statusFilter []RegionOptStatus,
	maxResults int,
	nextToken string,
) ([]*Region, string, error)

ListRegions returns regions filtered by opt-in status, honouring AWS's maxResults/nextToken pagination. nextToken is an opaque cursor (base64 of the exclusive-start RegionName); when maxResults <= 0 the full filtered list is returned.

func (*InMemoryBackend) PutAccountName

func (b *InMemoryBackend) PutAccountName(name string) error

PutAccountName updates the account's display name.

func (*InMemoryBackend) PutAlternateContact

func (b *InMemoryBackend) PutAlternateContact(contact *AlternateContact) error

PutAlternateContact creates or updates an alternate contact.

func (*InMemoryBackend) PutContactInformation

func (b *InMemoryBackend) PutContactInformation(info *ContactInformation) error

PutContactInformation sets primary contact information.

func (*InMemoryBackend) Reset

func (b *InMemoryBackend) Reset()

Reset clears all state.

func (*InMemoryBackend) Restore

func (b *InMemoryBackend) Restore(ctx context.Context, data []byte) error

Restore deserializes backend state from a snapshot. It implements persistence.Persistable.

func (*InMemoryBackend) Snapshot

func (b *InMemoryBackend) Snapshot(ctx context.Context) []byte

Snapshot serializes the backend state to JSON. It implements persistence.Persistable.

func (*InMemoryBackend) StartPrimaryEmailUpdate

func (b *InMemoryBackend) StartPrimaryEmailUpdate(email string) (string, error)

StartPrimaryEmailUpdate initiates a primary email change. Returns a fixed simulation OTP that the caller must pass to AcceptPrimaryEmailUpdate. Rejects a target email already in use by this account (ConflictException; see errPrimaryEmailInUse).

type Info

type Info struct {
	AccountID          string `json:"AccountId"`
	AccountName        string `json:"AccountName"`
	AccountCreatedDate string `json:"AccountCreatedDate"`
	AccountState       State  `json:"AccountState"`
}

Info holds the fields returned by GetAccountInformation.

type PrimaryEmailUpdateStatus added in v1.3.1

type PrimaryEmailUpdateStatus string

PrimaryEmailUpdateStatus represents the status of the most recent primary email update request, as reported by GetPrimaryEmailUpdateStatus.

const (
	PrimaryEmailUpdateStatusPending   PrimaryEmailUpdateStatus = "PENDING"
	PrimaryEmailUpdateStatusAccepted  PrimaryEmailUpdateStatus = "ACCEPTED"
	PrimaryEmailUpdateStatusCompleted PrimaryEmailUpdateStatus = "COMPLETED"
	PrimaryEmailUpdateStatusFailed    PrimaryEmailUpdateStatus = "FAILED"
)

type Provider

type Provider struct{}

Provider implements service.Provider for AWS Account Management.

func (*Provider) Init

Init initializes the Account Management service backend and handler.

func (*Provider) Name

func (p *Provider) Name() string

Name returns the provider name.

type Region

type Region struct {
	RegionName      string          `json:"RegionName"`
	RegionOptStatus RegionOptStatus `json:"RegionOptStatus"`
}

Region represents an AWS region and its opt-in status.

type RegionOptStatus

type RegionOptStatus string

RegionOptStatus represents the opt-in status of an AWS region.

const (
	RegionOptStatusEnabled        RegionOptStatus = "ENABLED"
	RegionOptStatusDisabled       RegionOptStatus = "DISABLED"
	RegionOptStatusEnabling       RegionOptStatus = "ENABLING"
	RegionOptStatusDisabling      RegionOptStatus = "DISABLING"
	RegionOptStatusEnabledDefault RegionOptStatus = "ENABLED_BY_DEFAULT"
)

type State

type State string

State represents the lifecycle state of an AWS account as reported by GetAccountInformation. Real Account Management never transitions an account to SUSPENDED/CLOSED/PENDING_ACTIVATION from this service -- account closure is an AWS Organizations concept (see the CloseAccount operation already implemented by services/organizations), so this service's backend always reports ACTIVE.

const (
	StateActive            State = "ACTIVE"
	StatePendingActivation State = "PENDING_ACTIVATION"
	StateSuspended         State = "SUSPENDED"
	StateClosed            State = "CLOSED"
)

type StorageBackend

type StorageBackend interface {
	Reset()
	GetAccountInformation() (*Info, error)
	ListRegions(statusFilter []RegionOptStatus, maxResults int, nextToken string) ([]*Region, string, error)
	EnableRegion(regionName string) error
	DisableRegion(regionName string) error
	GetRegionOptStatus(regionName string) (RegionOptStatus, error)
	GetAlternateContact(ContactType) (*AlternateContact, error)
	PutAlternateContact(*AlternateContact) error
	DeleteAlternateContact(ContactType) error
	GetContactInformation() (*ContactInformation, error)
	PutContactInformation(*ContactInformation) error
	GetPrimaryEmail() string
	StartPrimaryEmailUpdate(email string) (string, error)
	AcceptPrimaryEmailUpdate(otp, email string) error
	GetPrimaryEmailUpdateStatus() (PrimaryEmailUpdateStatus, time.Time, error)
	PutAccountName(name string) error
	GetGovCloudAccountInformation() (string, State, error)

	// Snapshot and Restore implement persistence.Persistable. Handler
	// delegates to them (see persistence.go) so a persistence manager that
	// registers Account can pick it up.
	Snapshot(ctx context.Context) []byte
	Restore(ctx context.Context, data []byte) error
}

StorageBackend defines the interface for the account service backend.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL