Firstlume Docs firstlume.io ENPT PT Talk to us

Organizations, folders, stacks

Firstlume organizes infrastructure as a tree: organization → folders → stacks. The tree belongs to you, not to the layout of your repositories. Settings defined high in the tree are inherited below, and any level can override them.

Organizations

An installation has many organizations. Each one has a display name and a slug, the identifier in URLs (lowercase letters, numbers and hyphens, 2 to 40 characters). All data (folders, stacks, runs, agents, variables, connections) belongs to exactly one organization, and nothing crosses between them.

Folders

A folder is a free-form node in the tree. Folders are optional: an organization can keep every stack at the top.

  • Names have 1 to 100 characters, can't contain /, and are unique among siblings, ignoring case.
  • Folders can nest up to 10 levels.
  • A folder can be renamed. It can only be deleted when empty.
  • Moving a folder isn't supported yet.

Stacks

A stack is one managed infrastructure. It sits in a folder or at the top of the organization, and it points to:

  • a repository
  • a branch, by default the repository's main branch
  • a path: the folder in the repository that contains .firstlume/config.yaml, such as environments/prod, or . for the root
environments/
├── prod/
│   ├── .firstlume/config.yaml   → stack with path environments/prod
│   └── main.tf
└── edge/
    ├── .firstlume/config.yaml   → stack with path environments/edge
    └── main.tf

Several stacks can come from the same repository and branch, with different paths. Each one has its own state, lock, runs, variables and settings. Two stacks in an organization can't share the same repository, branch and path, since they would manage the same infrastructure with different states.

Deleting a stack doesn't destroy infrastructure. A stack with an active run, or with resources in its state, can't be deleted.

Moving a stack

A stack can move to another folder or to the top: drag it in the tree, or use "Move…" on its page. The UI first shows what changes in what it inherits. The move is refused while the stack has a run queued, planning, awaiting approval or applying, or if the destination already has a stack with that name. Runs, state and versions stay with the stack.

Inheritance

For each setting, the value comes from the first level that defines it, going up from the stack:

stack → its folder → parent folder → ... → top folder → organization
Setting API field When no level defines it
Require approval before apply require_approval required
Drift check interval drift_interval_minutes off
Confirm each deletion or replacement confirm_destructive off
Vault role vault_role none
Terraform, environment and file variables variables none
Registry credentials, combined by host registries none

The identity of a variable is its category plus its name, so region as a Terraform variable and region as an environment variable are different things. Secrets are variables with sensitive: true and follow the same rule. Their values are never returned by the API at any level.

You can override an inherited variable, but you can't remove it at a lower level.

Example

Organization Acme          TF_VAR_region=us-east-1, secret DB_PASSWORD=a, approval=yes
└── Infra                  (nothing)
    ├── prod               secret DB_PASSWORD=b, drift=every 6h
    │   └── stack cluster  (nothing)
    │                      → region=us-east-1 (Acme), DB_PASSWORD=b (prod),
    │                        approval=yes (Acme), drift=6h (prod)
    └── dev                approval=no
        └── stack dev01    TF_VAR_region=sa-east-1
                           → region=sa-east-1 (stack), DB_PASSWORD=a (Acme),
                             approval=no (dev), drift=off (default)

At any level, the UI shows what is defined there, what is inherited and from where, and what that level overrides.

When values are read

  • The plan uses the effective variables at the moment it starts.
  • The apply uses the same variables as the plan, from a snapshot stored encrypted in the run, even if someone changes a folder in between.
  • The approval rule is read when the plan finishes.

Settings in the API

GET|PUT /api/v1/orgs/{org}/settings
GET|PUT /api/v1/orgs/{org}/folders/{id}/settings
GET|PUT /api/v1/orgs/{org}/stacks/{id}/settings

A PUT replaces what the level defines. Send the level's settings and variables each time. A setting left out goes back to inheriting. A sensitive variable sent with an empty value keeps its stored value. The one exception is registries: without the field, the level's credentials stay as they are.

Git connection

An organization can connect to one Git account. Gitea is the first supported provider. In Gitea, the account is an organization or a user, and the credential is a service token from a bot account, with read access to the repositories. The token is separate from anyone's login, so nothing stops when someone leaves. It is encrypted and never returned by the API.

With the connection, Firstlume lists the account's repositories and finds the .firstlume folders in a branch without cloning. It marks each one as valid or invalid, and shows whether a stack already uses it. The "New stack" wizard is built on this.

Without a connection, a stack can use any Git repository by its clone URL, with an optional token.

Members and access

Every signed-in user with access to an organization is an administrator of it. Finer roles are planned.

Who sees what

Who Organizations they see Can create organizations
Admin token all yes
Installation administrator, a member of a group in auth.oidc.adminGroups all yes
Any other signed-in user only those they are a member of no

An organization you aren't a member of answers 404 on every route, including stacks, runs and state, so its existence isn't revealed. Someone with no organization sees a screen with their login, ready to send to an administrator, and no way to create one.

auth.oidc.allowedGroups only decides who can sign in. It gives no access to any organization: that takes an invitation, or being an installation administrator.

Invitations

Members and installation administrators invite people by their Gitea login:

curl -s -H "$H" $O/members -d '{"login": "maria"}'
  • Someone who has signed in before becomes a member immediately.
  • Someone who never signed in gets a pending invitation, which takes effect at their first sign-in. Logins are compared ignoring case.
  • Pending invitations appear in the member list, can be canceled, and expire after 30 days. Firstlume doesn't check whether the login exists, so a typo shows up as an invitation nobody accepts.
  • Removing a member takes effect immediately, even with a session open, and doesn't cancel runs they already started.

Runs, approvals and setting changes record who did them: the person's login, or admin-token.