@gambi97/keel-cli 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,3 +21,21 @@ output "database_url" {
21
21
  output "container_namespace_id" {
22
22
  value = scaleway_container_namespace.this.id
23
23
  }
24
+
25
+ output "object_bucket_name" {
26
+ value = var.enable_object_storage ? scaleway_object_bucket.files[0].name : null
27
+ }
28
+
29
+ output "object_bucket_endpoint" {
30
+ value = var.enable_object_storage ? "https://s3.${var.region}.scw.cloud" : null
31
+ }
32
+
33
+ output "object_storage_access_key" {
34
+ value = var.enable_object_storage ? scaleway_iam_api_key.storage[0].access_key : null
35
+ sensitive = true
36
+ }
37
+
38
+ output "object_storage_secret_key" {
39
+ value = var.enable_object_storage ? scaleway_iam_api_key.storage[0].secret_key : null
40
+ sensitive = true
41
+ }
@@ -47,6 +47,11 @@ variable "enable_basic_auth" {
47
47
  type = bool
48
48
  }
49
49
 
50
+ variable "enable_object_storage" {
51
+ type = bool
52
+ default = false
53
+ }
54
+
50
55
  variable "secret_environment_variables" {
51
56
  description = "Secrets injected into the container, sourced from Infisical."
52
57
  type = map(string)
@@ -18,3 +18,25 @@ output "container_namespace_id" {
18
18
  description = "Scaleway Containers namespace ID."
19
19
  value = module.app_stack.container_namespace_id
20
20
  }
21
+
22
+ output "object_bucket_name" {
23
+ description = "Object Storage bucket for application files (null unless enabled)."
24
+ value = module.app_stack.object_bucket_name
25
+ }
26
+
27
+ # The complete set of secrets the pipeline pushes to Infisical after each apply:
28
+ # always DATABASE_URL, plus the S3_* coordinates when Object Storage is enabled.
29
+ output "infisical_secrets" {
30
+ description = "Secrets synced to Infisical after each apply."
31
+ sensitive = true
32
+ value = merge(
33
+ { DATABASE_URL = module.app_stack.database_url },
34
+ var.enable_object_storage ? {
35
+ S3_BUCKET = module.app_stack.object_bucket_name
36
+ S3_ENDPOINT = module.app_stack.object_bucket_endpoint
37
+ S3_REGION = var.region
38
+ S3_ACCESS_KEY = module.app_stack.object_storage_access_key
39
+ S3_SECRET_KEY = module.app_stack.object_storage_secret_key
40
+ } : {}
41
+ )
42
+ }
@@ -13,8 +13,8 @@ variable "environment" {
13
13
  type = string
14
14
 
15
15
  validation {
16
- condition = contains(["staging", "prod"], var.environment)
17
- error_message = "environment must be either \"staging\" or \"prod\"."
16
+ condition = contains(__ENV_SLUGS_TF__, var.environment)
17
+ error_message = "environment must be one of the configured environments."
18
18
  }
19
19
  }
20
20
 
@@ -72,6 +72,12 @@ variable "enable_basic_auth" {
72
72
  default = false
73
73
  }
74
74
 
75
+ variable "enable_object_storage" {
76
+ description = "When true, provision an Object Storage bucket for the app plus a dedicated least-privilege credential; its coordinates are synced to Infisical as S3_*."
77
+ type = bool
78
+ default = false
79
+ }
80
+
75
81
  variable "infisical_host" {
76
82
  description = "Infisical instance URL."
77
83
  type = string
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Pushes the ready-to-use database connection string (dedicated IAM
3
- # credential included) to Infisical as DATABASE_URL.
4
- # Usage: sync-database-url.sh <staging|prod>
5
- # Expects: INFISICAL_HOST, INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET,
6
- # INFISICAL_PROJECT_ID in the environment; terraform init already run.
7
- set -euo pipefail
8
-
9
- ENVIRONMENT="${1:?usage: sync-database-url.sh <staging|prod>}"
10
-
11
- DB_URL="$(terraform output -raw database_url)"
12
- if [ -z "$DB_URL" ]; then
13
- echo "No database_url in outputs, skipping Infisical sync."
14
- exit 0
15
- fi
16
- echo "::add-mask::$DB_URL"
17
-
18
- ACCESS_TOKEN="$(curl -sS --fail-with-body -X POST \
19
- "$INFISICAL_HOST/api/v1/auth/universal-auth/login" \
20
- -H "Content-Type: application/json" \
21
- -d "{\"clientId\":\"$INFISICAL_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CLIENT_SECRET\"}" \
22
- | jq -r .accessToken)"
23
- echo "::add-mask::$ACCESS_TOKEN"
24
-
25
- payload="$(jq -n \
26
- --arg workspaceId "$INFISICAL_PROJECT_ID" \
27
- --arg environment "$ENVIRONMENT" \
28
- --arg value "$DB_URL" \
29
- '{workspaceId: $workspaceId, environment: $environment, secretPath: "/", secretValue: $value, type: "shared"}')"
30
-
31
- # Update the placeholder seeded at bootstrap; create the secret if missing.
32
- status="$(curl -sS -o /dev/null -w "%{http_code}" -X PATCH \
33
- "$INFISICAL_HOST/api/v3/secrets/raw/DATABASE_URL" \
34
- -H "Authorization: Bearer $ACCESS_TOKEN" \
35
- -H "Content-Type: application/json" \
36
- -d "$payload")"
37
-
38
- if [ "$status" = "404" ]; then
39
- curl -sS --fail-with-body -o /dev/null -X POST \
40
- "$INFISICAL_HOST/api/v3/secrets/raw/DATABASE_URL" \
41
- -H "Authorization: Bearer $ACCESS_TOKEN" \
42
- -H "Content-Type: application/json" \
43
- -d "$payload"
44
- elif [ "$status" -ge 300 ]; then
45
- echo "Failed to update DATABASE_URL in Infisical (HTTP $status)" >&2
46
- exit 1
47
- fi
48
-
49
- echo "DATABASE_URL synced to Infisical ($ENVIRONMENT)."
@@ -1,103 +0,0 @@
1
- name: Terraform apply
2
-
3
- on:
4
- push:
5
- branches: [main]
6
-
7
- permissions:
8
- contents: read
9
-
10
- concurrency:
11
- group: terraform-apply
12
- cancel-in-progress: false
13
-
14
- env:
15
- # The Scaleway keys double as S3 credentials for the state backend, so the
16
- # same secret feeds both variables: one credential, one place to rotate.
17
- AWS_ACCESS_KEY_ID: ${{ secrets.SCW_ACCESS_KEY }}
18
- AWS_SECRET_ACCESS_KEY: ${{ secrets.SCW_SECRET_KEY }}
19
- SCW_ACCESS_KEY: ${{ secrets.SCW_ACCESS_KEY }}
20
- SCW_SECRET_KEY: ${{ secrets.SCW_SECRET_KEY }}
21
- SCW_DEFAULT_PROJECT_ID: ${{ secrets.SCW_DEFAULT_PROJECT_ID }}
22
- SCW_DEFAULT_ORGANIZATION_ID: ${{ secrets.SCW_DEFAULT_ORGANIZATION_ID }}
23
- INFISICAL_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID }}
24
- INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }}
25
- INFISICAL_PROJECT_ID: ${{ vars.INFISICAL_PROJECT_ID }}
26
- INFISICAL_HOST: ${{ vars.INFISICAL_HOST }}
27
- TF_VAR_infisical_client_id: ${{ secrets.INFISICAL_CLIENT_ID }}
28
- TF_VAR_infisical_client_secret: ${{ secrets.INFISICAL_CLIENT_SECRET }}
29
- TF_VAR_infisical_project_id: ${{ vars.INFISICAL_PROJECT_ID }}
30
- TF_VAR_infisical_host: ${{ vars.INFISICAL_HOST }}
31
- TF_IN_AUTOMATION: "true"
32
-
33
- jobs:
34
- apply-staging:
35
- name: apply (staging)
36
- runs-on: ubuntu-latest
37
- environment: staging
38
- steps:
39
- - uses: actions/checkout@v4
40
-
41
- - uses: hashicorp/setup-terraform@v3
42
- with:
43
- terraform_version: "~1.12"
44
- terraform_wrapper: false
45
-
46
- - name: Write backend config
47
- run: |
48
- cat > backend.hcl <<EOF
49
- bucket = "${{ vars.TF_STATE_BUCKET }}"
50
- region = "${{ vars.SCW_REGION }}"
51
- endpoints = {
52
- s3 = "https://s3.${{ vars.SCW_REGION }}.scw.cloud"
53
- }
54
- EOF
55
-
56
- - name: Terraform init
57
- run: terraform init -input=false -backend-config=backend.hcl
58
-
59
- - name: Select workspace
60
- run: terraform workspace select -or-create staging
61
-
62
- - name: Terraform apply
63
- run: terraform apply -input=false -auto-approve -var-file=staging.tfvars
64
-
65
- - name: Sync DATABASE_URL to Infisical
66
- run: ./.github/scripts/sync-database-url.sh staging
67
-
68
- apply-prod:
69
- name: apply (prod)
70
- runs-on: ubuntu-latest
71
- needs: apply-staging
72
- # The "production" GitHub Environment carries a required-reviewer rule,
73
- # so this job waits for manual approval.
74
- environment: production
75
- steps:
76
- - uses: actions/checkout@v4
77
-
78
- - uses: hashicorp/setup-terraform@v3
79
- with:
80
- terraform_version: "~1.12"
81
- terraform_wrapper: false
82
-
83
- - name: Write backend config
84
- run: |
85
- cat > backend.hcl <<EOF
86
- bucket = "${{ vars.TF_STATE_BUCKET }}"
87
- region = "${{ vars.SCW_REGION }}"
88
- endpoints = {
89
- s3 = "https://s3.${{ vars.SCW_REGION }}.scw.cloud"
90
- }
91
- EOF
92
-
93
- - name: Terraform init
94
- run: terraform init -input=false -backend-config=backend.hcl
95
-
96
- - name: Select workspace
97
- run: terraform workspace select -or-create prod
98
-
99
- - name: Terraform apply
100
- run: terraform apply -input=false -auto-approve -var-file=prod.tfvars
101
-
102
- - name: Sync DATABASE_URL to Infisical
103
- run: ./.github/scripts/sync-database-url.sh prod
@@ -1,7 +0,0 @@
1
- # Non-sensitive production configuration. Safe to commit.
2
- project_name = "__PROJECT_NAME__"
3
- region = "__REGION__"
4
- environment = "prod"
5
- enable_basic_auth = false
6
- min_scale = __PROD_MIN_SCALE__
7
- max_scale = __PROD_MAX_SCALE__
@@ -1,7 +0,0 @@
1
- # Non-sensitive staging configuration. Safe to commit.
2
- project_name = "__PROJECT_NAME__"
3
- region = "__REGION__"
4
- environment = "staging"
5
- enable_basic_auth = true
6
- min_scale = __STAGING_MIN_SCALE__
7
- max_scale = __STAGING_MAX_SCALE__