@staticforge/azure 0.0.0-stage → 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +6 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/clients.d.ts +23 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +85 -0
- package/dist/clients.js.map +1 -0
- package/dist/deployer.d.ts +20 -0
- package/dist/deployer.d.ts.map +1 -0
- package/dist/deployer.js +343 -0
- package/dist/deployer.js.map +1 -0
- package/dist/history.d.ts +37 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +49 -0
- package/dist/history.js.map +1 -0
- package/dist/iac.d.ts +27 -0
- package/dist/iac.d.ts.map +1 -0
- package/dist/iac.js +188 -0
- package/dist/iac.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/rebuild.d.ts +15 -0
- package/dist/rebuild.d.ts.map +1 -0
- package/dist/rebuild.js +97 -0
- package/dist/rebuild.js.map +1 -0
- package/dist/swa-config.d.ts +19 -0
- package/dist/swa-config.d.ts.map +1 -0
- package/dist/swa-config.js +136 -0
- package/dist/swa-config.js.map +1 -0
- package/dist/uploader.d.ts +24 -0
- package/dist/uploader.d.ts.map +1 -0
- package/dist/uploader.js +58 -0
- package/dist/uploader.js.map +1 -0
- package/package.json +52 -3
- package/terraform/modules/site/main.tf +38 -0
- package/terraform/modules/site/outputs.tf +27 -0
- package/terraform/modules/site/variables.tf +44 -0
- package/terraform/modules/site/versions.tf +10 -0
- package/terraform/state-bootstrap/main.tf +83 -0
- package/terraform/state-bootstrap/outputs.tf +21 -0
- package/terraform/state-bootstrap/variables.tf +53 -0
- package/terraform/state-bootstrap/versions.tf +14 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploader.js","sourceRoot":"","sources":["../src/uploader.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@staticforge/azure",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Azure provider for staticforge: Static Web Apps, named preview environments, rollback by rebuild",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"staticforge",
|
|
7
|
+
"azure",
|
|
8
|
+
"static-web-apps",
|
|
9
|
+
"opentofu",
|
|
10
|
+
"terraform"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/elchanio-76/sforge#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/elchanio-76/sforge/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/elchanio-76/sforge.git",
|
|
19
|
+
"directory": "packages/providers/azure"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Eleftherios Chaniotakis",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"@staticforge/source": "./src/index.ts",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"default": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"terraform/**/*.tf",
|
|
34
|
+
"terraform/**/*.hcl",
|
|
35
|
+
"!terraform/**/.terraform.lock.hcl",
|
|
36
|
+
"!terraform/**/tests/**"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": "^22.22.0 || >=24.8.0"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@azure/arm-appservice": "^19.0.0",
|
|
46
|
+
"@azure/arm-storage": "^21.0.0",
|
|
47
|
+
"@azure/identity": "^4.14.0",
|
|
48
|
+
"@azure/static-web-apps-cli": "^2.1.0",
|
|
49
|
+
"@azure/storage-blob": "^12.34.0",
|
|
50
|
+
"@staticforge/build": "0.1.1",
|
|
51
|
+
"@staticforge/core": "0.1.1",
|
|
52
|
+
"@staticforge/iac": "0.1.1",
|
|
53
|
+
"@staticforge/provider-api": "0.1.1"
|
|
54
|
+
}
|
|
6
55
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# An Azure Static Web App that sforge deploys to with the SWA deployment client.
|
|
2
|
+
# The app is not linked to a repository: content arrives through `sforge deploy`,
|
|
3
|
+
# which fetches the deployment token at run time (it is not an output and not in
|
|
4
|
+
# any file sforge writes).
|
|
5
|
+
|
|
6
|
+
locals {
|
|
7
|
+
# Static Web App names are 2-60 characters.
|
|
8
|
+
app_name = substr("${var.name}-${var.target}", 0, 60)
|
|
9
|
+
tags = merge(var.tags, { "sforge:role" = "site" })
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
resource "azurerm_resource_group" "site" {
|
|
13
|
+
count = var.create_resource_group ? 1 : 0
|
|
14
|
+
|
|
15
|
+
name = var.resource_group_name
|
|
16
|
+
location = var.location
|
|
17
|
+
tags = local.tags
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
data "azurerm_resource_group" "site" {
|
|
21
|
+
count = var.create_resource_group ? 0 : 1
|
|
22
|
+
|
|
23
|
+
name = var.resource_group_name
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
resource "azurerm_static_web_app" "site" {
|
|
27
|
+
name = local.app_name
|
|
28
|
+
resource_group_name = var.create_resource_group ? azurerm_resource_group.site[0].name : data.azurerm_resource_group.site[0].name
|
|
29
|
+
location = var.location
|
|
30
|
+
|
|
31
|
+
sku_tier = var.sku
|
|
32
|
+
sku_size = var.sku
|
|
33
|
+
|
|
34
|
+
# Named preview environments (`sforge deploy --preview pr-42`).
|
|
35
|
+
preview_environments_enabled = true
|
|
36
|
+
|
|
37
|
+
tags = local.tags
|
|
38
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
output "static_web_app_name" {
|
|
2
|
+
value = azurerm_static_web_app.site.name
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
output "static_web_app_id" {
|
|
6
|
+
value = azurerm_static_web_app.site.id
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
output "resource_group" {
|
|
10
|
+
value = var.resource_group_name
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
output "location" {
|
|
14
|
+
value = var.location
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
output "sku" {
|
|
18
|
+
value = var.sku
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
output "default_host_name" {
|
|
22
|
+
value = azurerm_static_web_app.site.default_host_name
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
output "url" {
|
|
26
|
+
value = "https://${azurerm_static_web_app.site.default_host_name}"
|
|
27
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
variable "name" {
|
|
2
|
+
description = "Project name (iac.name), used in resource names and tags."
|
|
3
|
+
type = string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
variable "target" {
|
|
7
|
+
description = "Target name, e.g. prod."
|
|
8
|
+
type = string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
variable "resource_group_name" {
|
|
12
|
+
description = "Resource group of the site."
|
|
13
|
+
type = string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "create_resource_group" {
|
|
17
|
+
description = "Create the resource group (and delete it with the site). False uses an existing one."
|
|
18
|
+
type = bool
|
|
19
|
+
default = true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
variable "location" {
|
|
23
|
+
description = "Azure region. Static Web Apps are only available in a few (westus2, centralus, eastus2, westeurope, eastasia)."
|
|
24
|
+
type = string
|
|
25
|
+
validation {
|
|
26
|
+
condition = contains(["westus2", "centralus", "eastus2", "westeurope", "eastasia"], var.location)
|
|
27
|
+
error_message = "Static Web Apps are available in westus2, centralus, eastus2, westeurope and eastasia."
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
variable "sku" {
|
|
32
|
+
description = "Free or Standard."
|
|
33
|
+
type = string
|
|
34
|
+
default = "Free"
|
|
35
|
+
validation {
|
|
36
|
+
condition = contains(["Free", "Standard"], var.sku)
|
|
37
|
+
error_message = "sku must be \"Free\" or \"Standard\"."
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
variable "tags" {
|
|
42
|
+
type = map(string)
|
|
43
|
+
default = {}
|
|
44
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Remote state for every staticforge site in one Azure subscription.
|
|
2
|
+
# State files are stored in a private blob container at <site>/<target>.tfstate,
|
|
3
|
+
# authenticated with Microsoft Entra ID (no access keys) and locked with blob leases.
|
|
4
|
+
|
|
5
|
+
data "azurerm_client_config" "current" {}
|
|
6
|
+
|
|
7
|
+
resource "azurerm_resource_group" "state" {
|
|
8
|
+
name = var.resource_group_name
|
|
9
|
+
location = var.location
|
|
10
|
+
tags = merge(var.tags, { "sforge:role" = "state" })
|
|
11
|
+
|
|
12
|
+
lifecycle {
|
|
13
|
+
prevent_destroy = true
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
resource "azurerm_storage_account" "state" {
|
|
18
|
+
name = var.storage_account_name
|
|
19
|
+
resource_group_name = azurerm_resource_group.state.name
|
|
20
|
+
location = azurerm_resource_group.state.location
|
|
21
|
+
|
|
22
|
+
account_kind = "StorageV2"
|
|
23
|
+
account_tier = "Standard"
|
|
24
|
+
account_replication_type = var.replication_type
|
|
25
|
+
|
|
26
|
+
min_tls_version = "TLS1_2"
|
|
27
|
+
https_traffic_only_enabled = true
|
|
28
|
+
allow_nested_items_to_be_public = false
|
|
29
|
+
shared_access_key_enabled = false
|
|
30
|
+
default_to_oauth_authentication = true
|
|
31
|
+
|
|
32
|
+
blob_properties {
|
|
33
|
+
versioning_enabled = true
|
|
34
|
+
|
|
35
|
+
delete_retention_policy {
|
|
36
|
+
days = var.retention_days
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
container_delete_retention_policy {
|
|
40
|
+
days = var.retention_days
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
tags = merge(var.tags, { "sforge:role" = "state" })
|
|
45
|
+
|
|
46
|
+
lifecycle {
|
|
47
|
+
prevent_destroy = true
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
resource "azurerm_storage_container" "state" {
|
|
52
|
+
name = var.container_name
|
|
53
|
+
storage_account_id = azurerm_storage_account.state.id
|
|
54
|
+
container_access_type = "private"
|
|
55
|
+
|
|
56
|
+
lifecycle {
|
|
57
|
+
prevent_destroy = true
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Owner and Contributor manage the account but cannot read blobs: data access is a separate role.
|
|
62
|
+
resource "azurerm_role_assignment" "caller" {
|
|
63
|
+
scope = azurerm_storage_account.state.id
|
|
64
|
+
role_definition_name = "Storage Blob Data Contributor"
|
|
65
|
+
principal_id = data.azurerm_client_config.current.object_id
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
resource "azurerm_role_assignment" "extra" {
|
|
69
|
+
for_each = toset(var.data_contributors)
|
|
70
|
+
|
|
71
|
+
scope = azurerm_storage_account.state.id
|
|
72
|
+
role_definition_name = "Storage Blob Data Contributor"
|
|
73
|
+
principal_id = each.value
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
resource "time_sleep" "role_propagation" {
|
|
77
|
+
create_duration = var.role_propagation_delay
|
|
78
|
+
|
|
79
|
+
depends_on = [
|
|
80
|
+
azurerm_role_assignment.caller,
|
|
81
|
+
azurerm_role_assignment.extra,
|
|
82
|
+
]
|
|
83
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Both depend on the role propagation, so the migration into the backend starts after it.
|
|
2
|
+
|
|
3
|
+
output "resource_group" {
|
|
4
|
+
value = azurerm_resource_group.state.name
|
|
5
|
+
depends_on = [time_sleep.role_propagation]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
output "storage_account" {
|
|
9
|
+
value = azurerm_storage_account.state.name
|
|
10
|
+
depends_on = [time_sleep.role_propagation]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
output "storage_account_id" {
|
|
14
|
+
value = azurerm_storage_account.state.id
|
|
15
|
+
depends_on = [time_sleep.role_propagation]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
output "container" {
|
|
19
|
+
value = azurerm_storage_container.state.name
|
|
20
|
+
depends_on = [time_sleep.role_propagation]
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
variable "resource_group_name" {
|
|
2
|
+
description = "Resource group of the state storage account, e.g. sforge-state."
|
|
3
|
+
type = string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
variable "location" {
|
|
7
|
+
description = "Azure region of the state storage account."
|
|
8
|
+
type = string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
variable "storage_account_name" {
|
|
12
|
+
description = "Globally unique name (3-24 lowercase letters and digits), e.g. sfstate0123456789ab."
|
|
13
|
+
type = string
|
|
14
|
+
validation {
|
|
15
|
+
condition = can(regex("^[a-z0-9]{3,24}$", var.storage_account_name))
|
|
16
|
+
error_message = "storage_account_name must be 3-24 lowercase letters and digits."
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
variable "container_name" {
|
|
21
|
+
description = "Blob container that holds the state files."
|
|
22
|
+
type = string
|
|
23
|
+
default = "tfstate"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
variable "replication_type" {
|
|
27
|
+
description = "Storage replication (LRS, ZRS, GRS, ...)."
|
|
28
|
+
type = string
|
|
29
|
+
default = "LRS"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
variable "retention_days" {
|
|
33
|
+
description = "Days that deleted blobs and containers (and so state files) stay recoverable."
|
|
34
|
+
type = number
|
|
35
|
+
default = 30
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
variable "data_contributors" {
|
|
39
|
+
description = "Object IDs of further principals that may read and write state. The caller always can."
|
|
40
|
+
type = list(string)
|
|
41
|
+
default = []
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
variable "role_propagation_delay" {
|
|
45
|
+
description = "Wait after granting data access: Azure RBAC takes minutes to take effect, and the state is migrated right after."
|
|
46
|
+
type = string
|
|
47
|
+
default = "120s"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
variable "tags" {
|
|
51
|
+
type = map(string)
|
|
52
|
+
default = {}
|
|
53
|
+
}
|