Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
16 changes: 6 additions & 10 deletions firestartr-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ defaultDomainName: default-domain
defaultOrgPermissions: view
defaultBranchStrategy: none
defaultFirestartrGroup: firestartr
defaultGroup: my-group # must be an existing group/team slug or one of the created by the bootstrap process

firestartr:
# Check latest available release at github.com/prefapp/gitops-k8s
Expand Down Expand Up @@ -139,6 +140,7 @@ All the parameters must be filled. When copy pasting this file, `<placeholders>`
- `defaultOrgPermissions`: default permissions for the organization members. Can be: `none`, `view` or `contribute`.
- `defaultBranchStrategy`: default branch strategy for the organization repositories. These are defined in the `branch_strategies.yaml` and `expander_branch_strategies.yaml` files. Currently, the bootstrap creates only a definition for `gitflow`, though more can be added after bootstrapping if needed. Allowed values: `none`, `gitflow` or `custom`.
- `defaultFirestartrGroup`: name of the group that will be used by Firestartr by default. It can be an already existing group, which will be imported and used in the bootstrapping process, or a new group that will be created by it.
- `defaultGroup`: slug of the group that will be used by Firestartr by default. It can be an already existing group, which will be imported and used as the owner of the system and domain created by the bootstrap process.
- `firestartr.operator`: Firestartr version to be used by the operator. Must be the name of an image tag, without the flavor (i.e., `v1.53.0` instead of `v1.53.0_full-aws` or `v1.53.0_slim`). You can check the latest available image version [here](https://github.com/prefapp/gitops-k8s/pkgs/container/gitops-k8s).
- `firestartr.cli`: Firestartr CLI version to be used in the importation process. You can check the latest available CLI version [here](https://github.com/prefapp/gitops-k8s/blob/main/.release-please-manifest.json#L2). Note that this CLI version **won't** be the version set as the `FIRESTARTR_CLI_VERSION` organization variable, which is set from the parameter store instead (`/firestartr/<customer-name>/firestartr-cli-version`).
- `pushFiles`: whether or not to push the files create to their respective repositories once the bootstrap process finishes. Each section has two parameters: `push`, which if `true` will push those files to `repo`, whose value should be the name of the repository where those files will be pushed to.
Expand Down Expand Up @@ -177,9 +179,7 @@ cloudProvider:
source: hashicorp/aws
type: aws
version: ~> 4.0
githubApp:
owner: <org>
botName: "fs-<org>[bot]"
github:
prefappBotPat: "<bot-pat>" # Prefapp Bot's PAT
operatorPat: "<operator-pat>" # Operator's PAT, used to commit to the org firestartr-<env>
```
Expand All @@ -188,10 +188,8 @@ All the parameters must be filled. When copy pasting this file, `<placeholders>`

The rest of the parameters of the `cloudProvider` section are the AWS S3 bucket credentials that will be used as the terraform backend for the `state-infra` repository.

- `githubApp.owner`: name of the GitHub organization where Firestartr will be installed.
- `githubApp.botName`: name of the GitHub App bot user.
- `githubApp.prefappBotPat`: Personal Access Token for the Prefapp Bot user, used to download the features from the features repository.
- `githubApp.operatorPat`: Personal Access Token for the Operator user, used to commit the deployment and ArgoCD application PRs to the `firestartr-<env>` organization.
- `github.prefappBotPat`: Personal Access Token for the Prefapp Bot user, used to download the features from the features repository.
- `github.operatorPat`: Personal Access Token for the Operator user, used to commit the deployment and ArgoCD application PRs to the `firestartr-<env>` organization.

#### 3.2 Azure terraform backend provider configuration (currently not supported)

Expand All @@ -211,10 +209,8 @@ cloudProvider:
source: hashicorp/aws
type: aws
version: ~> 4.0
githubApp:
github:
providerConfigName: github-app-provider-config-name
owner: "firestartr-test"
botName: "firestartr-local-development-app[bot]"
```

### 4. How to launch the bootstrap
Expand Down
10 changes: 4 additions & 6 deletions firestartr-bootstrap/argocd.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,17 @@ func (m *FirestartrBootstrap) RenderArgoCDApplications(
}

pathAppStateGithub := fmt.Sprintf(

"/firestartr/%s/argo-firestartr-%s.%s.Application.yaml",
"/apps/firestartr/%s/argo-firestartr-%s.%s.Application.yaml",
m.Bootstrap.Customer,
"state-github",
m.Bootstrap.Org,
m.Bootstrap.Org,
)

pathAppStateInfra := fmt.Sprintf(

"/firestartr/%s/argo-firestartr-%s.%s.Application.yaml",
"/apps/firestartr/%s/argo-firestartr-%s.%s.Application.yaml",
m.Bootstrap.Customer,
"state-infra",
m.Bootstrap.Org,
m.Bootstrap.Org,
)

return dag.Directory().WithNewFile(pathAppStateGithub, applicationStateGithub).WithNewFile(pathAppStateInfra, applicationStateInfra), nil
Expand Down
4 changes: 2 additions & 2 deletions firestartr-bootstrap/argocd_config_secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ func (m *FirestartrBootstrap) AddArgoCDSecrets(
patchedDir, err := safelyPatchYamlConfig(
ctx,
argoCDRepo.Directory("/repo"),
"kubernetes-sys-services/firestartr-pro/argo-configuration-secrets/values.yaml",
m.Bootstrap.Org,
fmt.Sprintf("kubernetes-sys-services/firestartr-%s/argo-configuration-secrets/values.yaml", m.Bootstrap.Env),
m.GhOrgLowerCase,
clientAccess,
Comment on lines 63 to 68
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

installationIdSecretRef still uses m.Bootstrap.Org in the Parameter Store path, but the rest of the PR introduces GhOrgLowerCase to ensure org references are lowercase for SSM keys. This will reintroduce the original casing bug for the ArgoCD installation-id lookup. Use m.GhOrgLowerCase when building this parameter path.

Copilot uses AI. Check for mistakes.
)

Expand Down
26 changes: 23 additions & 3 deletions firestartr-bootstrap/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,17 @@ func (m *FirestartrBootstrap) CmdInitGithubAppsMachinery(
return nil, errorMessage
}

m.PopulateGithubAppCredsFromSecrets(ctx, kindContainer)
err = m.PopulateGithubAppCredsFromSecrets(ctx, kindContainer)
if err != nil {
errorMessage := PrepareAndPrintError(
ctx,
"CmdInitGithubAppsMachinery",
"An error occurred while populating the GitHub App credentials from the Kubernetes secrets",
err,
)

return nil, errorMessage
}

tokenSecret, err := m.GenerateGithubToken(ctx)
if err != nil {
Expand All @@ -183,7 +193,6 @@ func (m *FirestartrBootstrap) CmdInitGithubAppsMachinery(
return nil, errorMessage
}

m.Bootstrap.BotName = m.Creds.GithubApp.BotName
m.Bootstrap.HasFreePlan, err = m.OrgHasFreePlan(ctx, tokenSecret)
if err != nil {
errorMessage := PrepareAndPrintError(
Expand All @@ -208,6 +217,18 @@ func (m *FirestartrBootstrap) CmdInitGithubAppsMachinery(
return nil, errorMessage
}

err = m.CheckIfDefaultGroupExists(ctx, tokenSecret)
if err != nil {
errorMessage := PrepareAndPrintError(
ctx,
"CmdInitGithubAppsMachinery",
fmt.Sprintf("An error occurred while checking if the %s group exists", m.Bootstrap.DefaultGroup),
err,
)

return nil, errorMessage
}

successMessage := `
=====================================================
🤖 GITHUB APPS MACHINERY VALIDATED 🤖
Expand Down Expand Up @@ -529,7 +550,6 @@ func (m *FirestartrBootstrap) CmdPushStateSecrets(
}
}

m.Bootstrap.BotName = m.Creds.GithubApp.BotName
m.Bootstrap.HasFreePlan, err = m.OrgHasFreePlan(ctx, tokenSecret)
if err != nil {
errorMessage := PrepareAndPrintError(
Expand Down
8 changes: 4 additions & 4 deletions firestartr-bootstrap/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (m *FirestartrBootstrap) RenderDeployment(

m.Bootstrap.Customer,
m.Bootstrap.Customer,
m.GhOrg,
m.GhOrgLowerCase,
),
GithubAppPem: fmt.Sprintf(

Expand Down Expand Up @@ -140,7 +140,7 @@ func (m *FirestartrBootstrap) RenderDeployment(

m.Bootstrap.Customer,
m.Bootstrap.Customer,
m.GhOrg,
m.GhOrgLowerCase,
),
GithubAppPem: fmt.Sprintf(

Expand Down Expand Up @@ -183,8 +183,8 @@ func (m *FirestartrBootstrap) RenderDeployment(
}

deploymentDir := dag.Directory().
WithNewFile("pro.yaml", renderedPre).
WithNewFile("pro/values.yaml", renderedValues)
WithNewFile(fmt.Sprintf("%s.yaml", m.Bootstrap.Env), renderedPre).
WithNewFile(fmt.Sprintf("%s/values.yaml", m.Bootstrap.Env), renderedValues)

return deploymentDir, nil
}
8 changes: 4 additions & 4 deletions firestartr-bootstrap/external_secrets/bootstrap_secrets.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ spec:
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Customer }}/fs-{{ $.Customer }}-admin/pem"
key: "/firestartr/{{ $.Bootstrap.Customer }}/fs-{{ $.Bootstrap.Customer }}-admin/pem"
metadataPolicy: None
secretKey: fs-admin-pem
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Customer }}/fs-{{ $.Customer }}-admin/app-id"
key: "/firestartr/{{ $.Bootstrap.Customer }}/fs-{{ $.Bootstrap.Customer }}-admin/app-id"
metadataPolicy: None
secretKey: fs-admin-appid
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Customer }}/fs-{{ $.Customer }}-admin/{{ $.Org }}/app-installation-id"
key: "/firestartr/{{ $.Bootstrap.Customer }}/fs-{{ $.Bootstrap.Customer }}-admin/{{ $.GhOrgLowerCase }}/app-installation-id"
metadataPolicy: None
secretKey: fs-admin-installationid
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Customer }}/prefapp-bot-pat"
key: "/firestartr/{{ $.Bootstrap.Customer }}/prefapp-bot-pat"
metadataPolicy: None
secretKey: prefapp-bot-pat
refreshInterval: 24h0m0s
Expand Down
38 changes: 38 additions & 0 deletions firestartr-bootstrap/external_secrets/operator_secrets.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: operator-secrets
spec:
data:
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Bootstrap.Customer }}/fs-{{ $.Bootstrap.Customer }}/pem"
metadataPolicy: None
secretKey: fs-pem
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Bootstrap.Customer }}/fs-{{ $.Bootstrap.Customer }}/app-id"
metadataPolicy: None
secretKey: fs-appid
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Bootstrap.Customer }}/fs-{{ $.Bootstrap.Customer }}/{{ $.GhOrgLowerCase }}/app-installation-id"
metadataPolicy: None
secretKey: fs-installationid
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: "/firestartr/{{ $.Bootstrap.Customer }}/prefapp-bot-pat"
metadataPolicy: None
secretKey: prefapp-bot-pat
refreshInterval: 24h0m0s
secretStoreRef:
kind: SecretStore
name: aws
target:
creationPolicy: Owner
deletionPolicy: Delete
name: operator-secrets
33 changes: 33 additions & 0 deletions firestartr-bootstrap/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,39 @@ func (m *FirestartrBootstrap) WorkflowRun(
return nil
}

func (m *FirestartrBootstrap) CheckIfDefaultGroupExists(
ctx context.Context,
ghToken *dagger.Secret,
) error {
ctr, err := m.GhContainer(ctx, ghToken)
if err != nil {
return err
}

_, err = ctr.
WithEnvVariable("BUST_CACHE", time.Now().String()).
WithExec([]string{
"gh", "api", fmt.Sprintf("/orgs/%s/teams/%s", m.GhOrg, m.Bootstrap.DefaultGroup),
}).
Comment on lines +455 to +457
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This GitHub API endpoint expects a team slug (and should be URL path-escaped). Passing DefaultGroup verbatim will fail for teams whose display name contains spaces or other characters (the README example uses a space). Either validate/require defaultGroup to be the team slug (e.g., my-group) and document it, or apply url.PathEscape (and/or resolve the slug by name via the API) before calling gh api.

Copilot uses AI. Check for mistakes.
Sync(ctx)

switch err := err.(type) {
case nil:
return nil
case *dagger.ExecError:
errMsg := extractErrorMessage(
err,
fmt.Sprintf(
"Failed to check if %s group exists in the organization",
m.Bootstrap.DefaultGroup,
),
)
return errors.New(errMsg)
default:
return err
}
}

func (m *FirestartrBootstrap) CheckIfOrgAllGroupExists(
ctx context.Context,
ghToken *dagger.Secret,
Expand Down
6 changes: 3 additions & 3 deletions firestartr-bootstrap/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (m *FirestartrBootstrap) BuildHelmValues(
Secret: Secret{
Type: "Opaque",
Data: map[string]string{
"GITHUB_APP_PEM_FILE": m.Creds.GithubApp.Pem,
"GITHUB_APP_PEM_FILE": m.Creds.GithubAppOperator.Pem,
},
},
Config: Config{
Expand All @@ -63,8 +63,8 @@ func (m *FirestartrBootstrap) BuildHelmValues(
}, ","),
"OPERATOR_NAMESPACE": "default",
"OPERATOR_IGNORE_LEASE": "true",
"GITHUB_APP_ID": m.Creds.GithubApp.GhAppId,
"GITHUB_APP_INSTALLATION_ID": m.Creds.GithubApp.InstallationId,
"GITHUB_APP_ID": m.Creds.GithubAppOperator.GhAppId,
"GITHUB_APP_INSTALLATION_ID": m.Creds.GithubAppOperator.InstallationId,
"PREFAPP_BOT_PAT": m.Creds.GithubApp.PrefappBotPat,
"NODE_TLS_REJECT_UNAUTHORIZED": "0",
"ORG": m.GhOrg,
Expand Down
4 changes: 2 additions & 2 deletions firestartr-bootstrap/helm/firestartr-init/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ labels:
deploy:
replicas: 1
image:
name: bitnami/kubectl
name: bitnami/kubectl
tag: latest
pullPolicy: IfNotPresent
command:
command:
- "tail"
- "-f"
- "/dev/null"
Expand Down
Loading
Loading