Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,39 @@ deployments:
Kind is declared once under `secrets` or `variables`. Connectors map kind to the provider primitive (GitHub secrets vs variables APIs; Vercel `type: sensitive` vs `encrypted`). SST supports secrets only — non-secret SST config belongs in code as [Linkables](https://sst.dev/docs/component/linkable/).

> **Breaking:** Vercel `scope.sensitive` is removed. Put sensitive values under `deployment.secrets` and plaintext under `deployment.variables`.
>
> **Breaking:** Vercel destinations require `teamId`. Project env deployments need `scope.kind: environment` (and destination `project`). Team shared env uses `scope.kind: shared-environment` with optional `scope.projects`.

Vercel destination modes (selected by `scope.kind`):

```yaml
destinations:
vercel:
connector: vercel
teamId: team_xyz # required
project: prj_abc # optional; required for kind: environment
auth:
tokenEnv: VERCEL_TOKEN

deployments:
- name: vercel-production
set: production
destination: vercel
scope:
kind: environment
targets: [production]
secrets:
apiKey: API_KEY
- name: vercel-shared
set: production
destination: vercel
scope:
kind: shared-environment
targets: [production]
projects: [prj_abc, prj_def] # optional link set
secrets:
sharedSecret: SHARED_SECRET
```

## Deploy secrets

Expand Down
2 changes: 2 additions & 0 deletions examples/secretsync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ deployments:
set: production
destination: vercel
scope:
kind: environment
targets: [production]
secrets:
secretOneProd: SECRET_ONE
Expand All @@ -80,6 +81,7 @@ deployments:
set: staging
destination: vercel
scope:
kind: environment
targets: [preview]
secrets:
secretOneStaging: SECRET_ONE
Expand Down
53 changes: 44 additions & 9 deletions src/secretsync/application/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,8 @@ def _validate_deployments(
f"'{destination.connector}'"
)

if destination.connector == "vercel" and "sensitive" in deployment.scope:
raise ConfigInvalidError(
f"Deployment '{deployment.name}' uses deprecated scope.sensitive on Vercel",
hint=(
"Remove scope.sensitive. Put sensitive values under deployment.secrets "
"and plaintext under deployment.variables; the vercel connector sets "
"type from kind."
),
)
if destination.connector == "vercel":
_validate_vercel_deployment(deployment, destination)

available = composed[deployment.set]
kinds_used: set[ValueKind] = set()
Expand Down Expand Up @@ -199,6 +192,48 @@ def _validate_deployments(
)


def _validate_vercel_deployment(deployment: DeploymentDefinition, destination: object) -> None:
from secretsync.destinations.vercel import _project, _team_id, _validate_scope

dest_cfg = destination.model_dump(by_alias=True) # type: ignore[attr-defined]
if _team_id(dest_cfg) is None:
raise ConfigInvalidError(
f"Destination '{deployment.destination}' (vercel) requires teamId",
hint="Set destinations.<name>.teamId to your Vercel team id (team_…)",
)
if "sensitive" in deployment.scope:
raise ConfigInvalidError(
f"Deployment '{deployment.name}' uses deprecated scope.sensitive on Vercel",
hint=(
"Remove scope.sensitive. Put sensitive values under deployment.secrets "
"and plaintext under deployment.variables; the vercel connector sets "
"type from kind."
),
)
kinds: list[ValueKind] = []
if deployment.secrets:
kinds.append(ValueKind.SECRET)
if deployment.variables:
kinds.append(ValueKind.VARIABLE)
if not kinds:
kinds.append(ValueKind.SECRET)
project = _project(dest_cfg)
for kind in kinds:
reason = _validate_scope(
deployment.scope,
kind=kind,
destination_project=project,
)
if reason:
raise ConfigInvalidError(
f"Deployment '{deployment.name}' has invalid Vercel scope: {reason}",
hint=(
"Use scope.kind: environment (requires destination.project) or "
"shared-environment (optional scope.projects)."
),
)


def _record_target(
seen_targets: set[tuple[str, str, str, str]],
deployment: DeploymentDefinition,
Expand Down
Loading