Skip to content

Releases: iblai/infra-cli

v1.13.0

Choose a tag to compare

@bnsoni bnsoni released this 03 Jul 00:46
f5fb13a

Summary

Adds Google Cloud as a first-class provider for single-server deployments, alongside AWS — same wizard, same .env flows, same setup step.

  • Terraform stack (templates/gcp/single-server/): VPC + regional subnet, firewall rules (SSH restricted to the operator IP; health checks from Google's probe ranges), Compute Engine VM (Ubuntu 22.04, metadata SSH keys), unmanaged instance group behind a global external Application Load Balancer with a static IP, Google-managed SSL certificate (all platform subdomains, async validation), Cloud DNS A-records (existing zone auto-detected, or created with nameservers printed for registrar delegation)
  • Health check probes the LMS heartbeat with a learn.<domain> Host header — GCP accepts only a literal 200, and probing / hits the platform nginx catch-all's 301, marking the backend UNHEALTHY and serving 503 "no healthy upstream" for everything (hit live on the first bootstrap; designed out + regression-tested)
  • CloudProvider axis on InfraConfig (default aws; existing state files deserialize unchanged) + GCPCredentials (ADC or service-account key); runner dispatches templates/tfvars/env on it
  • PROVIDER=gcp non-interactive path + .env.provision.gcp.example; iblai infra permissions --provider gcp [--check]
  • One version prompt: setup/resetup ask for the prod-images release tag and resolve the matching iblai-cli-ops tag from its [tool.uv.sources] pin (uv ignores that table on git-URL installs, so the explicit install stays — only the question goes away). Stale 3.19.0 default removed from every input layer
  • Fixes: setup prompts crashed on GCP-provisioned states (no AWS credential block); iblai infra waf now cleanly rejects non-AWS stacks; GCP env builder surfaces validation errors instead of tracebacks
  • Docs: README rewrite (quick start, both clouds, ADC vs service-account walkthroughs, sample .env index) + step-by-step docs/GCP.md
  • Object storage remains on AWS S3 by design — operators supply credentials at the setup step (documented)

Test plan

  • 750 unit tests passing (GCP provider/runner/prompts/env suites mirror the AWS patterns)
  • terraform validate + fmt clean on the GCP templates
  • Verified live end-to-end on a real GCP project: provision (37 resources) → full 16-role bootstrap → platform serving over HTTPS behind the LB → teardown clean

🤖 Generated with Claude Code

v1.12.0

Choose a tag to compare

@bnsoni bnsoni released this 26 Jun 18:42
da4bb53

[1.12.0] — 2026-06-26

Fixed

  • TimescaleDB extension now created during DM bootstrap — the DM postgres image ships TimescaleDB preloaded (shared_preload_libraries=timescaledb), but the flow only ever ran CREATE EXTENSION vector; timescaledb was never created, so setup_timescale_views --full-setup (which ran under ignore_errors: true) silently degraded and analytics hypertables were never built. The ibl_dm role now runs CREATE EXTENSION IF NOT EXISTS timescaledb right after pgvector (idempotent, postgres-superuser). Confirmed against a field environment whose DB had only plpgsql + vector.
  • Microsoft SSO now uses the standard azuread-oauth2 backend — the microsoft_sso_config role derived the provider backend_name (and the /auth/login + /auth/complete SSO URLs) from platform_name (e.g. main-oauth2), which is not a registered Azure AD social-auth backend, so sign-in never completed and operators had to hand-fix the LMS OAuth2ProviderConfig. All backend references — OAuth2ProviderConfig.backend_name, the IBL_EDX.IBL_EDX_BASE_OAUTH_SSO_BACKEND block (IBL_OAUTH_SSO_NAME / TRACKED_PROVIDERS), other_settings.backend_uri, and IBL_SPA.AUTH.IBL_DIRECT_SSO_URL — now use the constant azuread-oauth2, matching the provider slug and the Azure-registered redirect URI. other_settings.platform_key still carries the tenant platform_name.
  • setup_timescale_views failures now surface — replaced the blanket ignore_errors: true on the data_seeding "Setup TimescaleDB views" task with a register + failed_when (fails on a genuine Python traceback, tolerates benign non-zero exits / idempotent re-runs) and a debug that prints the command output.

Added

  • IBL_DM.ENABLE_RBAC_GROUP_MANAGEMENT=true set by default — added to the ibl_platform "Enable DM RBAC" block alongside the existing ENABLE_RBAC / ENABLE_RBAC_SEEDING / ENABLE_TIMESCALEDB defaults (previously had to be set by hand).
  • Azure AD redirect-URI prerequisite documented.env.setup.example and the microsoft_sso_config end-of-run confirmation now spell out the exact redirect URI the client must register in their Azure AD app: https://learn.<BASE_DOMAIN>/auth/complete/azuread-oauth2/.

v1.11.0

Choose a tag to compare

@bnsoni bnsoni released this 01 Jun 20:17
0fe62ac

[1.11.0] — 2026-06-01

Added

  • Optional AWS WAFv2 on the single-server ALB — opt-in at provision time via the wizard (a new sub-step of "Domain & Certificates" — default off), provision-env (ENABLE_WAF=true + WAF_ALLOWED_IPS=… in the .env), or launch / launch-env (--enable-waf + --waf-allowed-ips, or matching env keys). Attaches a Regional WAFv2 Web ACL to the ALB with rules tuned for ibl.ai's subdomain layout: admin-only allow rules (gated on an operator IP allowlist) for DM Swagger UI, edX Studio (CMS), Django /admin/, and DM /data; public allow rule for learn.<base> and apps.learn.<base>; six AWS managed rule groups (IpReputation, KnownBadInputs, Common, SQLi, WordPress, PHP); and a path-traversal block for .git / .env / .htaccess / .svn / .hg / .DS_Store. Total estimated WCU ≈ 1355 (under the 1500 default). Allowlist accepts both bare IPs (auto-suffixed /32) and CIDR.
  • iblai infra waf post-provision subgroup — toggle WAFv2 on an already-provisioned single-server stack without re-running the wizard. Four commands: enable [<name>] (interactive; on a project that already has WAF on, warns and prompts to update the allowlist with current IPs pre-filled), enable-env [<name>] -f .env (non-interactive, reads WAF_ALLOWED_IPS), disable <name> [--yes] (Y/N confirm by default; --yes for CI; removes the Web ACL + IPSet + association, leaves the ALB intact), status [<name>] (table of all WAF-eligible projects with no arg, detail panel with one). Rejects multi-server, call-server, bootstrap, and non-created projects up-front with a clear error. Subgroup module lives at src/iblai_infra/features/waf.py; the features/ package docstring documents the pattern for the next optional-feature toggles (SMTP, Stripe, SSO providers) so they can drop in with the same enable / enable-env / disable / status shape.
  • TerraformRunner.reapply() — shared helper for re-running Terraform on an existing workspace with the latest state.config. Re-copies .tf templates (so template fixes propagate), reads the existing terraform.tfvars to pin the original bucket_suffix (prevents accidental S3 bucket renames once the date-stamp window has rolled over), regenerates the rest of tfvars from state.config, then runs initplanapply. Returns parsed outputs. Used by both the new iblai infra waf <action> commands and the refactored iblai infra retry.
  • WAFv2 entries in REQUIRED_IAM_POLICY + a wafv2:ListWebACLs smoke check in check_permissions() so iblai infra permissions [--check] surfaces WAF readiness up-front instead of failing mid-apply.

Changed

  • _generate_tfvars(self, bucket_suffix: str | None = None) — accepts an optional pinned suffix. When None (today's default for first setup()), resolves the suffix from AWS as before. When provided, uses the pinned value. Load-bearing change for the new reapply() helper.
  • iblai infra retry now uses TerraformRunner.reapply() instead of inlining template-copy + init/plan/apply, removing a drift point with the new WAF subgroup. Behaviour is unchanged for operators: the existing failure-recovery guards and Route 53 CNAME conflict cleanup still run.

v1.10.1

Choose a tag to compare

@bnsoni bnsoni released this 20 May 09:26
67af9e9

Summary

Bumps the SPA-ready wait budget from 10 × 15s = 150s to 30 × 15s = 450s (7.5 min) across all six SPA wait tasks. Patch release 1.10.1.

v1.10.0

Choose a tag to compare

@bnsoni bnsoni released this 20 May 06:01
9169dbc

[1.10.0] — 2026-05-20

Added

  • ibl_tenant_platform ansible role — launches a tenant Platform (Platform + admin User + UserPlatformLink) via run_launch_steps when PLATFORM_NAME is set to anything other than main. NOT a raw Platform.objects.create() — the state machine fires every after_launch signal (default apps, edX hooks, UserPlatformLink flags). Wired into both playbook.yml (setup / setup-env) and launch_playbook.yml (launch / launch-env). Skips + logs on re-runs when the tenant already exists. Also writes PLATFORM_NAME=<KEY> (uppercase) at the root of /ibl/config.yml and enforces Platform.show_paywall=False + Platform.is_advertising=False as defense in depth. Surfaces the generated admin password via the IBLAI_FIXTURE_OUTPUT pipeline — printed once after the Rich Live display tears down, never persisted to disk.
  • Microsoft SSO writes IBL_SPA.AUTHmicrosoft_sso_config now also patches EXTERNAL_IDP_LOGOUT_URL and IBL_DIRECT_SSO_URL (using microsoft_sso_tenant_id, falling back to common), then restarts the Auth + Mentor SPAs so the new auth flow takes effect.
  • INSTANCE_RAM_GB helper + 32 GB memory warning — non-blocking heads-up suggesting 64 GB (e.g. m5.4xlarge / r5.2xlarge) when the operator picks a 32 GB instance. Always shown in the interactive provision wizard and provision-env; conditional in launch / launch-env (only when AI is enabled).
  • Final ibl global-proxy reload added as post_tasks in both playbook.yml and launch_playbook.yml, so any nginx state touched by SSO roles (edX restarts in google_sso_config / microsoft_sso_config) is reloaded before the playbook exits.
  • RESERVED_ADMIN_USERNAMES + RESERVED_PLATFORM_NAMESmodels.py constants, surfaced via is_reserved_admin_username() and is_reserved_platform_name() helpers and an InfraConfig model_validator.

Changed

  • Stripe billing UI off by defaultIBL_SPA.MENTOR.STRIPE_ENABLED=false and IBL_SPA.MENTOR.ENABLE_ADVERTISING=false are now written unconditionally by ibl_spa (fresh installs) and ibl_launch_services (AMI launches). Behavior change: Stripe-using deployments must explicitly flip IBL_SPA.MENTOR.STRIPE_ENABLED back to 'true' post-setup. The previous "always on" SPA flag surfaced billing UI even when Stripe wasn't actually configured.
  • 100 GB minimum root volume for single / multi server — enforced by Pydantic (InfraConfig model_validator gated on DeploymentType.SINGLE, plus MultiServerConfig.validate_volume_sizes) and matching interactive + CLI + .env input checks. Behavior change: values below 100 GB are now rejected upfront. Default ComputeConfig.volume_size bumped 50 → 100. Call-server unchanged (LiveKit only needs ~40 GB).
  • ADMIN_USERNAME=ibl_admin rejected at every input layer — reserved for the SPA OAuth Application owner the platform itself maintains. New default suggestion is platform_admin. Interactive prompts, .env parsers, and --admin-username flag all reject ibl_admin with a clear reserved-name error. Behavior change: scripted deploys passing ADMIN_USERNAME=ibl_admin must rename.
  • PLATFORM_NAME=main rejected as an explicit input — unset / blank silently resolves to main (preserving SSO backend_name=main-oauth2 and skipping the tenant launcher). Behavior change: scripted deploys passing PLATFORM_NAME=main should drop the line.
  • README — refreshed against current playbook (16 roles, phase-grouped table), three deployment topologies, sizing guidance, tenant launcher, reserved-name rules. -50 lines net.

Removed

  • All references to a specific canonical-client name from comments, docstrings, prompt instructions, error hints, and example .env files. Placeholders: <client> for monorepo org names, acme for tenant-key examples.

Fixed

  • Slow _test_ssh() retry-path tests — five tests in tests/ansible/test_runner.py exercise the SSH-retry exhaust path (10 retries × 15 s sleep). They now mock time.sleep alongside the existing subprocess.run mock, cutting ~11 minutes off the full suite. Test count: 562 passing in ~1.3 s.

v1.9.0

Choose a tag to compare

@bnsoni bnsoni released this 07 May 17:25
bc2411c
  • New: iblai infra provision-env -f .env — fresh single-server Terraform provision from a .env file, no AMI required (#51)
    • New: iblai infra setup-env [] -f .env — non-interactive Ansible bootstrap, supports both provisioned-name and
      free-standing-server modes (#53, #54)
    • New: .env.provision.example and .env.setup.example schema templates
    • Fix: ansible-core 2.19 parser error blocking 6 roles (google/microsoft SSO, SMTP, Stripe, data seeding, playwright) — converted
      free-form shell: | to dict form
    • Fix: .env parser now strips inline # comment from unquoted values
    • Fix: SMTP_PORT non-numeric values surface a clean error instead of a Python traceback
    • Fix: setup-env is idempotent — re-running resumes existing bootstrap state instead of clobbering
    • Tests: +55 new unit tests (552 total passing)

v1.7.0

Choose a tag to compare

@bnsoni bnsoni released this 06 May 00:47
8156745

[1.7.0] — 2026-05-06

Added

  • Optional Microsoft (Azure AD) SSO setup via a new microsoft_sso_config ansible role. When the operator opts in (Y/N prompt during iblai infra setup, or --microsoft-sso-client-id for iblai infra launch), the role does two things: (1) patches IBL_EDX.IBL_EDX_BASE_OAUTH_SSO_BACKEND in /ibl/config.yml via direct Python yaml manipulation (since the block has nested dicts + a list, which ibl config save --set cannot round-trip), runs ibl config save, and bounces edX so the new Django settings take effect; (2) creates an OAuth2ProviderConfig row on the LMS for the azuread-oauth2 slug, with backend_name derived from platform_name, sync_learner_profile_data=True, and a Microsoft-specific other_settings JSON carrying platform_key, backend_uri, and the Azure AD federated logout_url. Idempotent — the heavy ibl config save + edX restart only run when the config block actually differs from the desired state, and the OAuth2ProviderConfig save uses current(slug) to skip when the latest revision already matches
  • SetupConfig.platform_name — top-level field (defaults to main), prompted at the start of Step 2 (Platform Configuration). Lowercased + stripped on input. Drives both the SSO backend_name (<platform_name>-oauth2) and the other_settings.platform_key. Always populated; the SSO roles read it whether or not their feature flag is enabled
  • SetupConfig.microsoft_sso_* fieldsmicrosoft_sso_enabled, microsoft_sso_client_id, microsoft_sso_client_secret, microsoft_sso_tenant_id, microsoft_sso_organization. Client secret is Field(exclude=True) so it never lands in state.json
  • Launch CLI flags--platform-name (default main), --microsoft-sso-client-id (the trigger), --microsoft-sso-client-secret, --microsoft-sso-tenant-id, --microsoft-sso-organization. Same env-var pattern as Stripe / SMTP / Google SSO

v1.5.4

Choose a tag to compare

@gipsbrian gipsbrian released this 05 May 17:01
db445e1

What changed:

  • Pin direct runtime dependencies to currently running freeze versions for issue #1633 — updated pyproject.toml to exact pins for ansible-core==2.19.9, boto3==1.42.97, pydantic==2.13.3, questionary==2.1.1, rich==15.0.0, and typer==0.25.0, then regenerated uv.lock so lock and install metadata are aligned to the same tested dependency set.

closes: iblai/iblai-platform#1633

v1.3.0

Choose a tag to compare

@bnsoni bnsoni released this 02 Apr 18:48
80c52c2

What's Changed:

  • resetup command — re-configure existing environments with new domain + rotated secrets
  • launch command — non-interactive AMI-based provisioning + platform setup for CI/CD
  • launch-env command — launch from .env file with interactive confirmation
  • iblai-prod-images integration — CLI ops installed via iblai-images[sumac], all image versions pinned by the package (no more hardcoded tags)
  • Database password sync — PostgreSQL and MySQL passwords synced after secret rotation (capture-before-rotate pattern)
  • SPA health checks — all SPA launches verified via HTTP with retries
  • Ansible progress display — shows current task description instead of just "Running"
  • .env.example — template for launch variables with safe placeholders
  • Ingress system — pre-provisioned domain endpoint management with lock backends

v1.2.0

Choose a tag to compare

@bnsoni bnsoni released this 20 Mar 12:54
7e31126

[1.2.0] — 2026-03-20

Added

  • iblai infra bootstrap command — set up the IBL platform on any existing server (any cloud, bare metal) without Terraform provisioning
  • Interactive bootstrap wizard collects server IP, SSH key, domain, image tags, and AWS/GitHub credentials
  • Bootstrap projects tracked with provider="bootstrap"list, status, and destroy all work
  • Destroy guard for bootstrap projects skips Terraform teardown and marks project as destroyed
  • "Bootstrap existing server" option in landing screen menu