Commit Graph

9 Commits

Author SHA1 Message Date
vasyansk 9f0938daea fix: reject snapshot when template already attached (409); handle domains-load error; drop orphaned useDeleteDomain
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 12:54:52 +07:00
vasyansk 5662334799 fix(api): distinguish domain-not-found (404) from provider failure (502) on zone endpoints
Introduce service.ErrProviderUnavailable, wrapped only around the
provider GetRecords call in ZoneRecords. handleZoneRecords and
handleTemplateFromZone now use errors.Is against it to tell a real
provider outage (502) apart from local resolution failures such as an
unknown domain (404), instead of collapsing every ZoneRecords error
into a blanket 502. Also fixes handleTemplateFromZone's GetDomain
error branch to return 404 "domain not found" instead of 500, for
consistency with handleSetDomainTemplate/handleDomainHistory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-05 12:14:46 +07:00
vasyansk 9ccb304d2e feat(api): read zone records without template + snapshot-to-template
LoadDomain requires a template, so a zone without one could never be
viewed or snapshotted. Adds a template-free path: store.LoadZone /
service.ZoneRef / DomainService.ZoneRecords read a zone's live records
straight from the provider (no diff, no template). GET
/domains/{did}/records exposes read-only viewing; POST
/domains/{did}/template-from-zone snapshots only managed record types
(NS/SOA excluded) into a new template and auto-attaches it to the domain.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-05 12:00:27 +07:00
vasyansk 568452846a feat(api): structured provider credentials + trial-auth validation on account create
POST /accounts now accepts secret as a provider-specific JSON object
instead of an opaque string, and validates credentials via
provider.Provider.Validate before persisting — invalid credentials get
a generic 400 without ever reaching Store.CreateAccount or echoing the
secret back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 20:12:41 +07:00
vasyansk 32107571d1 feat(selectel): project-scoped IAM auth with token cache; provider Validate
Selectel Cloud DNS v2 requires a project IAM token in X-Auth-Token, not the
raw service-user secret; the previous client sent the static secret directly
and got 401. The client now parses Credentials.Secret as a Creds JSON blob
(username/password/account_id/project_name), exchanges it for a token via
the Identity API (POST /identity/v3/auth/tokens), and caches the token in
memory per-account until 5 minutes before expiry. ListZones/GetRecords/
ApplyChanges send the cached IAM token instead of the raw secret.

provider.Provider gains a Validate(ctx, Credentials) method so a bad account
can be rejected via trial login at creation time; all Provider fakes across
provider/registry/api/service test packages implement it as a no-op stub for
now (Task 2 will make api's mock configurable).

Security: the service-user password is folded into the token cache key via
SHA-256 (never stored in the clear) so a password change invalidates the
cached token; identity errors are generic and never echo the request body.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
2026-07-04 20:02:36 +07:00
vasyansk 4533b0ca25 feat(api): RequireAuth+RequireProjectAccess middleware, IDOR-scope check/apply по projectID 2026-07-03 20:47:40 +07:00
vasyansk ddab6e2162 fix(store,api): идемпотентный import (UNIQUE+ON CONFLICT) + PATCH привязки шаблона к домену 2026-07-03 15:24:08 +07:00
vasyansk 2aca92d070 fix(api): tenant-проверка account/template в CreateDomain (HIGH), атомарный import через транзакцию (MEDIUM) 2026-07-03 15:08:16 +07:00
vasyansk ae6a4d7f4c feat(api): CRUD accounts/templates/domains + import зон (полный цикл), secret не в ответах
Task 9 Фазы 1B: узкий интерфейс TenantStore (внутри store.Account/Template/Domain,
без db.* в api) реализован тонкими обёртками в internal/store/tenant.go; API.Store/
Cipher/Reg добавлены к существующему Svc. Роуты POST/GET/DELETE для accounts/
templates/domains + POST /accounts/{aid}/import (ListZones -> CreateDomain на зону).
accountResponse не содержит секрет ни в каком виде.
2026-07-03 14:53:29 +07:00