v0.12.0
minorHighlights
- ▸Deploys no longer depend on CodeBuild. When AWS reports no build capacity, Eigon falls back to kaniko running as an ordinary Fargate task — same Dockerfile, same registry, no Docker daemon and no build quota. Built because a CodeBuild concurrency limit of zero blocked every customer deploy on the account for six days
- ▸Databases are reachable again in every environment. The RDS stack granted Postgres ingress to the cluster security group while tasks ran under the per-service group, so the rule matched nothing. It was masked for months by a blanket 10.0.0.0/16 rule; removing that for tenant isolation turned a latent mismatch into total loss of connectivity
- ▸Failures say what actually happened. CloudFormation's resource-level reason is now read and fed into classification — previously the pipeline saw only 'sceptre launch: exit status 1', so a missing IAM action, an ECS circuit breaker and an invalid template were indistinguishable and all rendered as the same red banner
- ▸Plans belong to organisations again. One person can hold several, one per org — reversing 0.11.0's per-user model, which made it impossible to put two businesses on different tiers. Billing, invoices, seat limits and the plan picker are all org-scoped
- ▸Managed services from the console. Object storage and transactional email are addable per environment, priced at AWS list with no markup, and each one tells you the env vars your code will receive plus how to run an equivalent locally
- ▸Environments that go quiet hibernate instead of billing. Compute is reclaimed after sustained inactivity; data is snapshotted first and the customer's price is unchanged
- ▸Cost estimates match the invoice. A phantom NAT gateway, a missing IPv4 address charge and a second, untouched cost implementation were all overstating the number
Added
- +kaniko Fargate builder (pkg/imagebuild/fargatekaniko.go) — packs the already-cloned source to S3 and builds in an unprivileged Fargate task. Engages only on a capacity failure and only when configured; otherwise the original CodeBuild error is surfaced rather than a confusing second one. No git credentials reach the build task
- +CloudFormation failure reader (pkg/cfnfailure) — returns the resource-level reason a stack failed. Events arrive newest-first and a failing resource cancels its siblings, so a naive first-match returns 'Resource creation cancelled'; the cascade is skipped, with a fallback so an all-noise stack still reports something. Lives in pkg/ because the worker cannot import controlplane internals
- +Per-org billing (migration 0109) — restores UNIQUE(org_id), attaches each surviving subscription to the org with the most real workload rather than the oldest, and gives every other owned org its own Hobby row. Usage is measured per org, so a quiet side project no longer consumes the seats of the org paying for them
- +Managed services catalogue — S3 and SES provisioned per environment, grouped by whether they change the monthly floor. Each service documents what it holds, the deployed value's shape (never the value — a connection string carries a password) and a working local equivalent
- +Environment hibernation (migration 0105) — reclaims compute from environments idle beyond a threshold after alerting, snapshotting data first. Stateful workloads default to the safe class
- +Alert delivery (pkg/alerts) — outbox with exponential suppression, so a crash loop reports once and backs off instead of sending thousands of identical emails. Placed outside internal/ so the worker, which detects the failures, can actually send them
- +Build logs are persisted and root-caused, so a failed build has somewhere to look. Previously the CloudWatch location was read inside the poll loop and discarded
Improved
- ~Errors are no longer rendered as empty results. A revoked GitHub token showed 'No repositories found', a stale log group showed 'No logs available', and an expired session showed 'Couldn't load services' — each now names its cause, with a reconnect or retry path
- ~An org's billing page is reachable. The page, its API and RBAC all existed; it was missing from the sidebar, so a plan could only be seen or changed by typing the URL
- ~Enterprise can no longer be self-served. It is a contact-sales plan priced at zero, so any org admin could switch to unlimited limits for nothing. Custom plans are now refused outside the staff path
- ~Role no longer derives from billing state. An org owner whose trial had lapsed was shown as a member, because a 403 from the entitlements endpoint was indistinguishable from 'not an admin'
- ~Database passwords are allocated per environment from a CSPRNG instead of a predictable pattern, and are no longer passed as plaintext task-definition environment variables
- ~Log groups resolve to the one the service is actually writing to. Every stack replacement leaves a new group behind, and the resolver was picking whichever random suffix sorted lowest — often one last written to weeks earlier
- ~ECS task role granted logs:PutRetentionPolicy. Every generated service template sets retention, so without it the LogGroup resource failed AccessDenied and rolled back the whole service stack
- ~Attaching the cluster security group to tasks no longer blanks it. The parameter defaulted to an empty string and no stack config supplied one, so ECS rejected every service with 'security group cannot be blank' and rolled the stack back — the fix for database reachability had made all deploys fail. Both stack paths now pass a value, and the template drops the entry rather than emitting a blank
- ~An environment variable you set no longer collides with one Eigon sets. A name the template already emits appeared twice and CloudFormation refused the task definition outright, because the ECS schema requires unique entries. Your value wins
- ~Alerts about failed deploys are actually delivered. Every send since alerting shipped had failed against a mistyped table name, so nothing was ever sent — failures could only be found by opening the dashboard, which is what the alerts existed to avoid
- ~A failed deploy now tells you what broke, and whose fault it is. The banner read a field the API never sent, so it always showed the same generic text and the same “Add environment variables” button — which, for a failure inside Eigon, led to a page that then reported it could not find any missing variables. Ours now say so plainly and ask nothing of you
- ~Database migrations run on first deploy. The lookup that finds your environment's cluster compared two names that order their parts differently, so it never matched and migrations were skipped on every first deploy — leaving an application running healthily against an un-migrated schema
- ~The schema can be rebuilt from empty. Two migrations disagreed about the shape of one table, and the second silently did nothing, so building the database from scratch had been impossible — no new region, no restore. Feature flags were the table in question and had been reading the wrong columns in production
- ~Five queries named columns that do not exist — failure classification had never trained, LLM cost attribution never resolved, and deploy approval emails never found a recipient. Each failed silently at query time. A check now compares every SQL statement in the codebase against the real schema
- ~You are no longer emailed about our outages. A failure in Eigon's own machinery was sent to your team verbatim — one asked customers to install our build tool on a host they cannot reach. Failures are now routed by who can act on them: ours page us and never leave the building, yours name the stage that broke and link to the logs, and neither carries raw internal text
