magic-pocket-cli 0.18.1__tar.gz → 0.19.0__tar.gz
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.
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/PKG-INFO +2 -2
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/destroy_cli.py +39 -7
- magic_pocket_cli-0.19.0/pocket_cli/cli/image_cli.py +59 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/main_cli.py +2 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/neon_cli.py +29 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/mediator.py +44 -19
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/cloudformation.py +90 -13
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/cloudfront.py +46 -10
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/awscontainer.yaml +11 -1
- magic_pocket_cli-0.19.0/pocket_cli/templates/cloudformation/cf_function_basic_auth_prelude.js +11 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cloudfront.yaml +47 -10
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pyproject.toml +2 -2
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/.gitignore +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/__init__.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/__init__.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/aws_auth.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/awscontainer_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/cloudfront_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/cloudfront_keys_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/cloudfront_waf_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/deploy_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/dsql_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/migrate_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/permissions_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/rds_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/resource_helper.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/runtime_config_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/s3_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/status_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/store_url_helper.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/tidb_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/upstash_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/url_helper.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/vpc_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/cli/waf_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/django_cli.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/__init__.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/__init__.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/__init__.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/codebuild.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/depot.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/docker.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/dockerignore.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/ecr.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/efs.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/lambdahandler.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/poll.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/s3_utils.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/stack_backed.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/state.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/awscontainer.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/cloudfront_acm.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/cloudfront_keys.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/cloudfront_waf.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/dsql.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/neon.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/rds.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/s3.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/tidb.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/upstash.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/vpc.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cf_function_api_host.js +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cf_function_host_redirect_prelude.js +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cf_function_spa_auth.js +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cf_function_spa_fallback.js +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cloudfront_acm.yaml +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cloudfront_keys.yaml +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/cloudfront_waf.yaml +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/vpc.yaml +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/django-dotenv.env +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/django-settings.py +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/pocket.Dockerfile +0 -0
- {magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/pocket_simple.toml +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: magic-pocket-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: CLI and deploy tools for magic-pocket.
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: awscrt>=0.19.0
|
|
7
7
|
Requires-Dist: click>=8.1.7
|
|
8
8
|
Requires-Dist: deepdiff>=6.7.1
|
|
9
9
|
Requires-Dist: jinja2>=3.1.3
|
|
10
|
-
Requires-Dist: magic-pocket>=0.
|
|
10
|
+
Requires-Dist: magic-pocket>=0.19.0
|
|
11
11
|
Requires-Dist: pathspec>=1.0.4
|
|
12
12
|
Requires-Dist: python-on-whales>=0.68.0
|
|
13
13
|
Requires-Dist: pyyaml>=6.0.1
|
|
@@ -114,8 +114,18 @@ def _collect_external_database_targets(context: Context) -> list[str]:
|
|
|
114
114
|
if Upstash(context.upstash).database:
|
|
115
115
|
targets.append("Upstash Redis: %s" % context.upstash.database_name)
|
|
116
116
|
if context.neon and context.neon.provisioning != "command":
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
neon = Neon(context.neon)
|
|
118
|
+
if neon.branch:
|
|
119
|
+
plan = neon.destroy_plan()
|
|
120
|
+
if plan == "project":
|
|
121
|
+
targets.append(
|
|
122
|
+
"Neon プロジェクト '%s' (root branch のため project ごと削除)"
|
|
123
|
+
% context.neon.project_name
|
|
124
|
+
)
|
|
125
|
+
elif plan == "branch":
|
|
126
|
+
targets.append("Neon ブランチ")
|
|
127
|
+
# "blocked" (root だが他 branch 同居) は削除できないため一覧に載せない
|
|
128
|
+
# (destroy 実行時に警告する)
|
|
119
129
|
return targets
|
|
120
130
|
|
|
121
131
|
|
|
@@ -292,16 +302,38 @@ def _destroy_upstash(context: Context):
|
|
|
292
302
|
|
|
293
303
|
|
|
294
304
|
def _destroy_neon(context: Context):
|
|
295
|
-
"""Neon ブランチを削除 (provisioning="command" は管理外)
|
|
305
|
+
"""Neon ブランチを削除 (provisioning="command" は管理外)
|
|
306
|
+
|
|
307
|
+
root branch は Neon 仕様で branch 単位の削除ができない (422: cannot delete the
|
|
308
|
+
root branch) ため、project 内に他 branch が無ければ project ごと削除する。他
|
|
309
|
+
branch が同居している場合は巻き添えになるため何も消さず警告して続行する
|
|
310
|
+
(destroy 全体を異常終了させない)。
|
|
311
|
+
"""
|
|
296
312
|
if not context.neon:
|
|
297
313
|
return
|
|
298
314
|
if context.neon.provisioning == "command":
|
|
299
315
|
_warn_command_provisioned("Neon", "pocket resource neon delete")
|
|
300
316
|
return
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
317
|
+
neon = Neon(context.neon)
|
|
318
|
+
if not neon.branch:
|
|
319
|
+
return
|
|
320
|
+
plan = neon.destroy_plan()
|
|
321
|
+
if plan == "blocked":
|
|
322
|
+
echo.warning(
|
|
323
|
+
"Neon branch '%s' は root branch のため単体削除できず、project '%s' には"
|
|
324
|
+
"他の branch が残っているため project 削除も行いません。"
|
|
325
|
+
"他 stage の destroy 後に pocket resource neon delete で削除してください。"
|
|
326
|
+
% (context.neon.branch_name, context.neon.project_name)
|
|
327
|
+
)
|
|
328
|
+
return
|
|
329
|
+
if plan == "project":
|
|
330
|
+
echo.log("Destroying Neon project (root branch のため project ごと削除)...")
|
|
331
|
+
neon.delete_project()
|
|
332
|
+
echo.success("Neon project '%s' was deleted." % context.neon.project_name)
|
|
333
|
+
return
|
|
334
|
+
echo.log("Destroying Neon branch...")
|
|
335
|
+
neon.delete_branch()
|
|
336
|
+
echo.success("Neon branch was deleted.")
|
|
305
337
|
|
|
306
338
|
|
|
307
339
|
def _destroy_cloudfront_and_acm(context: Context):
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""deploy 済みコンテナイメージの参照情報を出力する CLI。
|
|
2
|
+
|
|
3
|
+
外部ツール (pocket と併走する deploy 系) が pocket のビルドしたイメージを
|
|
4
|
+
参照する際、pocket.toml を読んだ正確な値をスクリプトから取得できるようにする
|
|
5
|
+
(`pocket.naming.ecr_repo_name` の「toml を読む版」)。stdout には値のみを出し、
|
|
6
|
+
`$(pocket resource image uri --stage <s>)` の形で食えるようにする (診断は stderr)。
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from pocket.context import Context
|
|
12
|
+
from pocket_cli.cli.resource_helper import require_configured
|
|
13
|
+
from pocket_cli.resources.awscontainer import AwsContainer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.group()
|
|
17
|
+
def image():
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _get_awscontainer(stage: str) -> AwsContainer:
|
|
22
|
+
context = Context.from_toml(stage=stage)
|
|
23
|
+
return AwsContainer(
|
|
24
|
+
require_configured(
|
|
25
|
+
context.awscontainer, "awscontainer is not configured for this stage"
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@image.command()
|
|
31
|
+
@click.option("--stage", envvar="POCKET_DEPLOY_STAGE", prompt=True)
|
|
32
|
+
def repo(stage):
|
|
33
|
+
"""ECR repository 名を stdout に出力する (ecr_name 上書きを含め toml 準拠)。"""
|
|
34
|
+
ac = _get_awscontainer(stage)
|
|
35
|
+
click.echo(ac.context.ecr_name)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@image.command()
|
|
39
|
+
@click.option("--stage", envvar="POCKET_DEPLOY_STAGE", prompt=True)
|
|
40
|
+
def uri(stage):
|
|
41
|
+
"""deploy 済み実イメージの URI ({repo_uri}@{digest}) を stdout に出力する。
|
|
42
|
+
|
|
43
|
+
`:{stage}` タグが現在指している image を digest で固定した URI を返すため、
|
|
44
|
+
以後の deploy でタグが動いても参照が壊れない。
|
|
45
|
+
"""
|
|
46
|
+
ac = _get_awscontainer(stage)
|
|
47
|
+
ecr = ac.ecr
|
|
48
|
+
if not ecr.uri:
|
|
49
|
+
raise click.ClickException(
|
|
50
|
+
"ECR repository '%s' が見つかりません。先に `pocket deploy` を"
|
|
51
|
+
"実行してください。" % ac.context.ecr_name
|
|
52
|
+
)
|
|
53
|
+
digest = ecr.image_detail.image_digest
|
|
54
|
+
if not digest:
|
|
55
|
+
raise click.ClickException(
|
|
56
|
+
"tag ':%s' のイメージが '%s' に見つかりません。deploy 済みか確認して"
|
|
57
|
+
"ください。" % (stage, ac.context.ecr_name)
|
|
58
|
+
)
|
|
59
|
+
click.echo("%s@%s" % (ecr.uri, digest))
|
|
@@ -10,6 +10,7 @@ from pocket_cli.cli import (
|
|
|
10
10
|
deploy_cli,
|
|
11
11
|
destroy_cli,
|
|
12
12
|
dsql_cli,
|
|
13
|
+
image_cli,
|
|
13
14
|
migrate_cli,
|
|
14
15
|
neon_cli,
|
|
15
16
|
permissions_cli,
|
|
@@ -91,3 +92,4 @@ resource.add_command(s3_cli.s3)
|
|
|
91
92
|
resource.add_command(cloudfront_cli.cloudfront)
|
|
92
93
|
resource.add_command(cloudfront_keys_cli.cloudfront_keys)
|
|
93
94
|
resource.add_command(cloudfront_waf_cli.cloudfront_waf)
|
|
95
|
+
resource.add_command(image_cli.image)
|
|
@@ -69,12 +69,41 @@ def branch_out(stage, base_stage):
|
|
|
69
69
|
"--yes", "-y", is_flag=True, default=False, help="確認プロンプトをスキップ"
|
|
70
70
|
)
|
|
71
71
|
def delete(stage, yes):
|
|
72
|
+
"""stage の Neon ブランチを削除する。
|
|
73
|
+
|
|
74
|
+
root branch は Neon 仕様で branch 単位の削除ができない (422: cannot delete the
|
|
75
|
+
root branch) ため、project 内に他 branch が無ければ再確認のうえ project ごと
|
|
76
|
+
削除する。他 branch が同居している場合は巻き添えになるためエラーで中断する。
|
|
77
|
+
"""
|
|
72
78
|
if not yes:
|
|
73
79
|
click.confirm(
|
|
74
80
|
"stage '%s' の Neon ブランチを削除しますか?(データは失われます)" % stage,
|
|
75
81
|
abort=True,
|
|
76
82
|
)
|
|
77
83
|
neon = get_neon_resource(stage)
|
|
84
|
+
if neon.branch is None:
|
|
85
|
+
raise click.ClickException(
|
|
86
|
+
"Neon branch '%s' が見つかりません" % neon.context.branch_name
|
|
87
|
+
)
|
|
88
|
+
plan = neon.destroy_plan()
|
|
89
|
+
if plan == "blocked":
|
|
90
|
+
raise click.ClickException(
|
|
91
|
+
"branch '%s' は root branch のため単体削除できません (Neon 仕様)。"
|
|
92
|
+
"project '%s' には他の branch が残っているため project 削除も行いません。"
|
|
93
|
+
"他の branch を先に削除してください。"
|
|
94
|
+
% (neon.context.branch_name, neon.context.project_name)
|
|
95
|
+
)
|
|
96
|
+
if plan == "project":
|
|
97
|
+
if not yes:
|
|
98
|
+
click.confirm(
|
|
99
|
+
"branch '%s' は root branch のため、project '%s' を丸ごと削除します。"
|
|
100
|
+
"よろしいですか?"
|
|
101
|
+
% (neon.context.branch_name, neon.context.project_name),
|
|
102
|
+
abort=True,
|
|
103
|
+
)
|
|
104
|
+
neon.delete_project()
|
|
105
|
+
echo.success("Project '%s' was deleted." % neon.context.project_name)
|
|
106
|
+
return
|
|
78
107
|
neon.delete_branch()
|
|
79
108
|
echo.success("Branch was deleted successfully.")
|
|
80
109
|
|
|
@@ -108,26 +108,25 @@ class Mediator:
|
|
|
108
108
|
sc.pocket_store.delete_secret_keys(orphaned)
|
|
109
109
|
|
|
110
110
|
def _generate_secret(self, spec: ManagedSecretSpec):
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return secrets.token_hex(32)
|
|
129
|
-
else:
|
|
111
|
+
generators = {
|
|
112
|
+
"auto_database_url": self._get_auto_database_url,
|
|
113
|
+
"password": lambda: self._generate_password(spec.options),
|
|
114
|
+
"neon_database_url": self._get_neon_database_url,
|
|
115
|
+
"tidb_database_url": self._get_tidb_database_url,
|
|
116
|
+
"rds_database_url": self._get_rds_database_url,
|
|
117
|
+
"upstash_redis_url": self._get_upstash_redis_url,
|
|
118
|
+
"rsa_pem_base64": self._generate_rsa_pem,
|
|
119
|
+
"cloudfront_signing_key": self._generate_rsa_pem,
|
|
120
|
+
"spa_token_secret": lambda: secrets.token_hex(32),
|
|
121
|
+
"origin_verify_secret": lambda: secrets.token_hex(32),
|
|
122
|
+
"basic_auth_credential": lambda: self._generate_basic_auth_credential(
|
|
123
|
+
spec.options
|
|
124
|
+
),
|
|
125
|
+
}
|
|
126
|
+
generator = generators.get(spec.type)
|
|
127
|
+
if generator is None:
|
|
130
128
|
raise RuntimeError("Unknown secret type: %s" % spec.type)
|
|
129
|
+
return generator()
|
|
131
130
|
|
|
132
131
|
def _generate_rsa_pem(self) -> dict[str, str]:
|
|
133
132
|
try:
|
|
@@ -153,6 +152,32 @@ class Mediator:
|
|
|
153
152
|
"pub": base64.b64encode(pem_public_key).decode("utf-8"),
|
|
154
153
|
}
|
|
155
154
|
|
|
155
|
+
def _generate_basic_auth_credential(self, options):
|
|
156
|
+
"""Basic 認証の credential "user:pass" を生成する。
|
|
157
|
+
|
|
158
|
+
username は必須 (settings で検証済みだが直接呼び出しに備え再検証)。
|
|
159
|
+
password は options で固定値を指定でき、省略時は length/chars でランダム
|
|
160
|
+
生成する。固定値は pocket.toml (= git) に入る点に注意 (公開前サイトの
|
|
161
|
+
隠蔽用の共有credential を想定)。
|
|
162
|
+
"""
|
|
163
|
+
username = options.get("username")
|
|
164
|
+
if not isinstance(username, str) or not username or ":" in username:
|
|
165
|
+
raise Exception(
|
|
166
|
+
"basic_auth_credential requires options.username (str, ':' 不可)"
|
|
167
|
+
)
|
|
168
|
+
password = options.get("password")
|
|
169
|
+
if password is None:
|
|
170
|
+
# Basic 認証はブラウザ入力なので記号を避けた英数字既定にする
|
|
171
|
+
password = self._generate_password(
|
|
172
|
+
{
|
|
173
|
+
"length": options.get("length", 16),
|
|
174
|
+
"chars": options.get("chars", "abcdefghijkmnpqrstuvwxyz23456789"),
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
elif not isinstance(password, str) or not password:
|
|
178
|
+
raise Exception("basic_auth_credential options.password must be str")
|
|
179
|
+
return "%s:%s" % (username, password)
|
|
180
|
+
|
|
156
181
|
def _generate_password(self, options):
|
|
157
182
|
length = options.get("length", 16)
|
|
158
183
|
if not isinstance(length, int):
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/cloudformation.py
RENAMED
|
@@ -401,7 +401,10 @@ class CloudFrontStack(Stack):
|
|
|
401
401
|
|
|
402
402
|
@property
|
|
403
403
|
def _has_token_kvs(self) -> bool:
|
|
404
|
-
|
|
404
|
+
# KVS は spa auth の token_secret と basic_auth の期待ヘッダ値を共用する
|
|
405
|
+
return any(r.require_token for r in self.context.routes) or bool(
|
|
406
|
+
self.context.basic_auth
|
|
407
|
+
)
|
|
405
408
|
|
|
406
409
|
@property
|
|
407
410
|
def export(self):
|
|
@@ -477,6 +480,11 @@ class CloudFrontStack(Stack):
|
|
|
477
480
|
prelude = self._render_host_redirect_prelude()
|
|
478
481
|
if not prelude:
|
|
479
482
|
return code
|
|
483
|
+
return self._inject_after_request_line(code, prelude)
|
|
484
|
+
|
|
485
|
+
@staticmethod
|
|
486
|
+
def _inject_after_request_line(code: str, prelude: str) -> str:
|
|
487
|
+
"""`var request = event.request;` の直後に prelude を差し込む。"""
|
|
480
488
|
out: list[str] = []
|
|
481
489
|
injected = False
|
|
482
490
|
for line in code.splitlines():
|
|
@@ -486,6 +494,44 @@ class CloudFrontStack(Stack):
|
|
|
486
494
|
injected = True
|
|
487
495
|
return "\n".join(out)
|
|
488
496
|
|
|
497
|
+
def _render_basic_auth_prelude(self) -> str:
|
|
498
|
+
"""Basic 認証 prelude (4 スペース字下げ)。basic_auth 未設定なら空文字。"""
|
|
499
|
+
if not self.context.basic_auth:
|
|
500
|
+
return ""
|
|
501
|
+
env = Environment(
|
|
502
|
+
loader=PackageLoader("pocket_cli"),
|
|
503
|
+
autoescape=select_autoescape(),
|
|
504
|
+
)
|
|
505
|
+
template = env.get_template("cloudformation/cf_function_basic_auth_prelude.js")
|
|
506
|
+
return template.render().rstrip("\n")
|
|
507
|
+
|
|
508
|
+
def _inject_basic_auth(self, code: str) -> str:
|
|
509
|
+
"""生成済み Function コードに Basic 認証 prelude を差し込む
|
|
510
|
+
(basic_auth 有効時のみ)。
|
|
511
|
+
|
|
512
|
+
KVS 参照のため handler を async 化し、kvsHandle を持たない Function には
|
|
513
|
+
引数なし `cf.kvs()` (その Function に関連付けられた唯一の KVS を返す) の
|
|
514
|
+
宣言を前置する。呼び出し側はこの Function に KeyValueStoreAssociations を
|
|
515
|
+
必ず付けること (テンプレート側で basic_auth 時に一括付与)。
|
|
516
|
+
"""
|
|
517
|
+
prelude = self._render_basic_auth_prelude()
|
|
518
|
+
if not prelude:
|
|
519
|
+
return code
|
|
520
|
+
if "kvsHandle" not in code:
|
|
521
|
+
code = "import cf from 'cloudfront';\nconst kvsHandle = cf.kvs();\n" + code
|
|
522
|
+
if "async function handler" not in code:
|
|
523
|
+
code = code.replace("function handler(", "async function handler(", 1)
|
|
524
|
+
return self._inject_after_request_line(code, prelude)
|
|
525
|
+
|
|
526
|
+
def _inject_viewer_preludes(self, code: str) -> str:
|
|
527
|
+
"""全 viewer-request Function 共通の prelude 合成。
|
|
528
|
+
|
|
529
|
+
basic auth を先に差し込み、その後 host redirect を同じ位置に差し込むことで
|
|
530
|
+
実行順は host redirect → basic auth になる (非 canonical host はまず 301 し、
|
|
531
|
+
認証プロンプトは canonical domain でのみ出す)。
|
|
532
|
+
"""
|
|
533
|
+
return self._inject_host_redirect(self._inject_basic_auth(code))
|
|
534
|
+
|
|
489
535
|
@staticmethod
|
|
490
536
|
def _reindent(code: str, indent: int) -> str:
|
|
491
537
|
"""FunctionCode: | ブロック用に 2 行目以降を indent スペース字下げする。"""
|
|
@@ -509,6 +555,22 @@ class CloudFrontStack(Stack):
|
|
|
509
555
|
)
|
|
510
556
|
return self._reindent(code, 8)
|
|
511
557
|
|
|
558
|
+
def _generate_basic_auth_function(self) -> str:
|
|
559
|
+
"""viewer-request Function を持たない behavior 用の単体 Basic 認証 Function。
|
|
560
|
+
|
|
561
|
+
behavior に付けられる viewer-request Function は 1 つだけのため、
|
|
562
|
+
redirect_from 有効時は host redirect prelude もここに同居させる
|
|
563
|
+
(単体 HostRedirectFunction は basic_auth 時には生成しない)。
|
|
564
|
+
"""
|
|
565
|
+
code = (
|
|
566
|
+
"function handler(event) {\n"
|
|
567
|
+
" var request = event.request;\n"
|
|
568
|
+
" return request;\n"
|
|
569
|
+
"}"
|
|
570
|
+
)
|
|
571
|
+
code = self._inject_viewer_preludes(code)
|
|
572
|
+
return self._reindent(code, 8)
|
|
573
|
+
|
|
512
574
|
def _build_deploy_hash_function_codes(self) -> dict[str, str]:
|
|
513
575
|
"""deploy_hash route 用の hash prefix strip Function コードを生成する"""
|
|
514
576
|
codes: dict[str, str] = {}
|
|
@@ -525,30 +587,38 @@ class CloudFrontStack(Stack):
|
|
|
525
587
|
" return request;\n"
|
|
526
588
|
"}" % deploy_hash
|
|
527
589
|
)
|
|
528
|
-
code = self.
|
|
590
|
+
code = self._inject_viewer_preludes(code)
|
|
529
591
|
codes[route.yaml_key] = self._reindent(code, 8)
|
|
530
592
|
return codes
|
|
531
593
|
|
|
594
|
+
@staticmethod
|
|
595
|
+
def _spa_fallback_uri(route) -> str:
|
|
596
|
+
"""SPA fallback の書き換え先 URI を組み立てる。
|
|
597
|
+
|
|
598
|
+
path_pattern の glob (`/admin/*` 等) をそのまま連結するとリテラル URI に
|
|
599
|
+
`*` が残り (`/admin/*/index.html`)、S3 に該当キーが無く全リクエストが 403 に
|
|
600
|
+
なる。prefix 部分だけを使う (`/admin/*` → `/admin/index.html`)。catch-all
|
|
601
|
+
(path_pattern 空) は従来どおり `/index.html`。
|
|
602
|
+
"""
|
|
603
|
+
prefix = route.path_pattern.rstrip("*").rstrip("/")
|
|
604
|
+
return prefix + "/" + route.spa_fallback_html
|
|
605
|
+
|
|
532
606
|
def _generate_spa_fallback_function(self, route) -> str: # type: ignore
|
|
533
607
|
"""SPA URL フォールバック用 CloudFront Function コードを生成する"""
|
|
534
|
-
fallback_uri =
|
|
535
|
-
if not route.path_pattern:
|
|
536
|
-
fallback_uri = "/" + route.spa_fallback_html
|
|
608
|
+
fallback_uri = self._spa_fallback_uri(route)
|
|
537
609
|
env = Environment(
|
|
538
610
|
loader=PackageLoader("pocket_cli"),
|
|
539
611
|
autoescape=select_autoescape(),
|
|
540
612
|
)
|
|
541
613
|
template = env.get_template("cloudformation/cf_function_spa_fallback.js")
|
|
542
614
|
code = template.render(fallback_uri=fallback_uri)
|
|
543
|
-
code = self.
|
|
615
|
+
code = self._inject_viewer_preludes(code)
|
|
544
616
|
# FunctionCode: | の下は8スペース
|
|
545
617
|
return self._reindent(code, 8)
|
|
546
618
|
|
|
547
619
|
def _generate_spa_auth_function(self, route) -> str: # type: ignore
|
|
548
620
|
"""KVS + HMAC 検証付き async CloudFront Function コードを生成する"""
|
|
549
|
-
fallback_uri =
|
|
550
|
-
if not route.path_pattern:
|
|
551
|
-
fallback_uri = "/" + route.spa_fallback_html
|
|
621
|
+
fallback_uri = self._spa_fallback_uri(route)
|
|
552
622
|
env = Environment(
|
|
553
623
|
loader=PackageLoader("pocket_cli"),
|
|
554
624
|
autoescape=select_autoescape(),
|
|
@@ -558,7 +628,7 @@ class CloudFrontStack(Stack):
|
|
|
558
628
|
fallback_uri=fallback_uri,
|
|
559
629
|
login_path=route.login_path,
|
|
560
630
|
)
|
|
561
|
-
code = self.
|
|
631
|
+
code = self._inject_viewer_preludes(code)
|
|
562
632
|
# Fn::Sub の2パラメータ形式で - | の下は12スペース
|
|
563
633
|
return self._reindent(code, 12)
|
|
564
634
|
|
|
@@ -570,7 +640,7 @@ class CloudFrontStack(Stack):
|
|
|
570
640
|
)
|
|
571
641
|
template = env.get_template("cloudformation/cf_function_api_host.js")
|
|
572
642
|
code = template.render()
|
|
573
|
-
code = self.
|
|
643
|
+
code = self._inject_viewer_preludes(code)
|
|
574
644
|
return self._reindent(code, 8)
|
|
575
645
|
|
|
576
646
|
@property
|
|
@@ -582,21 +652,28 @@ class CloudFrontStack(Stack):
|
|
|
582
652
|
api_host_function_code = ""
|
|
583
653
|
if self.context.has_lambda_route:
|
|
584
654
|
api_host_function_code = self._generate_api_host_function()
|
|
655
|
+
# basic_auth 時、素の behavior には単体 BasicAuthFunction を付ける
|
|
656
|
+
# (redirect prelude も同居)。単体 HostRedirectFunction は非 basic_auth 時のみ。
|
|
657
|
+
basic_auth_function_code = ""
|
|
658
|
+
if self.context.basic_auth:
|
|
659
|
+
basic_auth_function_code = self._generate_basic_auth_function()
|
|
585
660
|
host_redirect_function_code = ""
|
|
586
|
-
if self.context.has_redirect_from:
|
|
661
|
+
if self.context.has_redirect_from and not self.context.basic_auth:
|
|
587
662
|
host_redirect_function_code = self._generate_host_redirect_function()
|
|
588
663
|
|
|
589
664
|
return self._render_yaml(
|
|
590
665
|
context_data=self.context.model_dump(
|
|
591
|
-
exclude={"signing_key", "token_secret"}
|
|
666
|
+
exclude={"signing_key", "token_secret", "basic_auth"}
|
|
592
667
|
),
|
|
593
668
|
signing_key=bool(self.context.signing_key),
|
|
669
|
+
basic_auth=bool(self.context.basic_auth),
|
|
594
670
|
acm_certificate_arn=acm_certificate_arn,
|
|
595
671
|
waf_acl_arn=waf_acl_arn,
|
|
596
672
|
function_codes=function_codes,
|
|
597
673
|
deploy_hash_function_codes=deploy_hash_function_codes,
|
|
598
674
|
api_host_function_code=api_host_function_code,
|
|
599
675
|
host_redirect_function_code=host_redirect_function_code,
|
|
676
|
+
basic_auth_function_code=basic_auth_function_code,
|
|
600
677
|
has_token_kvs=self._has_token_kvs,
|
|
601
678
|
origin_verify_secret=self._origin_verify_secret_value,
|
|
602
679
|
)
|
|
@@ -46,6 +46,8 @@ class CloudFront:
|
|
|
46
46
|
self.cf_client = boto3.client("cloudfront")
|
|
47
47
|
self._token_secret_value: str = ""
|
|
48
48
|
self._origin_verify_secret_value: str = ""
|
|
49
|
+
# Basic 認証の期待 Authorization ヘッダ値 ("Basic <base64(user:pass)>")
|
|
50
|
+
self._basic_auth_expected: str = ""
|
|
49
51
|
|
|
50
52
|
@property
|
|
51
53
|
def description(self):
|
|
@@ -80,6 +82,7 @@ class CloudFront:
|
|
|
80
82
|
deploy 済み hash と一致せず、毎回 REQUIRE_UPDATE になる。
|
|
81
83
|
"""
|
|
82
84
|
self._prepare_token_secret(mediator)
|
|
85
|
+
self._prepare_basic_auth(mediator)
|
|
83
86
|
self._prepare_origin_verify_secret(mediator)
|
|
84
87
|
|
|
85
88
|
def create(self, mediator: Mediator | None = None):
|
|
@@ -144,6 +147,32 @@ class CloudFront:
|
|
|
144
147
|
% self.context.token_secret
|
|
145
148
|
)
|
|
146
149
|
|
|
150
|
+
def _prepare_basic_auth(self, mediator: Mediator | None):
|
|
151
|
+
"""basic_auth の managed secret ("user:pass") から期待ヘッダ値を組み立てる。
|
|
152
|
+
|
|
153
|
+
値は CloudFront Function が比較する "Basic <base64(user:pass)>" 形式で、
|
|
154
|
+
テンプレートには入れず deploy 後に KVS へ書き込む (token_secret と同経路)。
|
|
155
|
+
"""
|
|
156
|
+
import base64
|
|
157
|
+
|
|
158
|
+
if not self.context.basic_auth:
|
|
159
|
+
return
|
|
160
|
+
if not mediator:
|
|
161
|
+
return
|
|
162
|
+
ac = mediator.context.awscontainer
|
|
163
|
+
if not ac or not ac.secrets:
|
|
164
|
+
return
|
|
165
|
+
secrets = ac.secrets.pocket_store.secrets
|
|
166
|
+
value = secrets.get(self.context.basic_auth)
|
|
167
|
+
if not isinstance(value, str) or ":" not in value:
|
|
168
|
+
echo.warning(
|
|
169
|
+
"basic_auth '%s' の値が 'user:pass' 形式ではありません"
|
|
170
|
+
% self.context.basic_auth
|
|
171
|
+
)
|
|
172
|
+
return
|
|
173
|
+
encoded = base64.b64encode(value.encode()).decode()
|
|
174
|
+
self._basic_auth_expected = "Basic %s" % encoded
|
|
175
|
+
|
|
147
176
|
def _prepare_origin_verify_secret(self, mediator: Mediator | None):
|
|
148
177
|
"""enable_origin_verify 時に origin verify secret の値を store から読む。
|
|
149
178
|
|
|
@@ -172,7 +201,13 @@ class CloudFront:
|
|
|
172
201
|
)
|
|
173
202
|
|
|
174
203
|
def _write_token_secret_to_kvs(self):
|
|
175
|
-
|
|
204
|
+
"""KVS に token_secret / basic_auth を書き込む (設定されているもののみ)。"""
|
|
205
|
+
entries = {
|
|
206
|
+
"token_secret": self._token_secret_value,
|
|
207
|
+
"basic_auth": self._basic_auth_expected,
|
|
208
|
+
}
|
|
209
|
+
entries = {k: v for k, v in entries.items() if v}
|
|
210
|
+
if not entries:
|
|
176
211
|
return
|
|
177
212
|
if not self.stack.output:
|
|
178
213
|
echo.warning("スタック出力が取得できません。KVS 書き込みをスキップします。")
|
|
@@ -184,15 +219,16 @@ class CloudFront:
|
|
|
184
219
|
kvs_client = boto3.client(
|
|
185
220
|
"cloudfront-keyvaluestore", region_name=self.context.region
|
|
186
221
|
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
222
|
+
for key, value in entries.items():
|
|
223
|
+
# put_key ごとに ETag が変わるため毎回 describe で取り直す
|
|
224
|
+
desc = kvs_client.describe_key_value_store(KvsARN=kvs_arn)
|
|
225
|
+
kvs_client.put_key(
|
|
226
|
+
KvsARN=kvs_arn,
|
|
227
|
+
Key=key,
|
|
228
|
+
Value=value,
|
|
229
|
+
IfMatch=desc["ETag"],
|
|
230
|
+
)
|
|
231
|
+
echo.info("KVS に %s を書き込みました" % key)
|
|
196
232
|
|
|
197
233
|
def upload_managed_assets(self):
|
|
198
234
|
"""managed_assets のファイルを S3 に同期する (全件 upload + 不要削除)。"""
|
|
@@ -156,6 +156,8 @@ Resources:
|
|
|
156
156
|
Properties:
|
|
157
157
|
FunctionName: "{{ handler.function_name }}"
|
|
158
158
|
PackageType: Image
|
|
159
|
+
Architectures:
|
|
160
|
+
- "{{ lambda_architecture }}"
|
|
159
161
|
MemorySize: "{{ handler.memory_size }}"
|
|
160
162
|
Timeout: "{{ handler.timeout }}"
|
|
161
163
|
# {% if handler.reserved_concurrency %}
|
|
@@ -172,8 +174,16 @@ Resources:
|
|
|
172
174
|
Environment:
|
|
173
175
|
Variables:
|
|
174
176
|
"POCKET_STAGE": "{{ stage }}"
|
|
177
|
+
# {# tojson で YAML セーフに埋め込む (値内の二重引用符等で ParserError にしない)。
|
|
178
|
+
# container 共通 envs に handler.envs をマージし handler 側を優先する。
|
|
179
|
+
# 重複キーを 2 回出さないよう共通側は handler.envs にあるキーをスキップ #}
|
|
175
180
|
# {% for env_key, value in envs.items() %}
|
|
176
|
-
|
|
181
|
+
# {% if env_key not in handler.envs %}
|
|
182
|
+
{{ env_key | tojson }}: {{ value | tojson }}
|
|
183
|
+
# {% endif %}
|
|
184
|
+
# {% endfor %}
|
|
185
|
+
# {% for env_key, value in handler.envs.items() %}
|
|
186
|
+
{{ env_key | tojson }}: {{ value | tojson }}
|
|
177
187
|
# {% endfor %}
|
|
178
188
|
# {% for env_key, import_name in signing_key_imports.items() %}
|
|
179
189
|
"{{ env_key }}":
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var __pocketBaAuth = request.headers.authorization;
|
|
2
|
+
var __pocketBaExpected;
|
|
3
|
+
try { __pocketBaExpected = await kvsHandle.get('basic_auth'); }
|
|
4
|
+
catch (e) { __pocketBaExpected = null; }
|
|
5
|
+
if (!__pocketBaExpected || !__pocketBaAuth || __pocketBaAuth.value !== __pocketBaExpected) {
|
|
6
|
+
return {
|
|
7
|
+
statusCode: 401,
|
|
8
|
+
statusDescription: 'Unauthorized',
|
|
9
|
+
headers: { 'www-authenticate': { value: 'Basic realm="Restricted"' } }
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -11,12 +11,15 @@ Resources:
|
|
|
11
11
|
SigningBehavior: always
|
|
12
12
|
SigningProtocol: sigv4
|
|
13
13
|
|
|
14
|
+
# {# basic_auth 時に素の behavior へ付ける単体 Function 名 (redirect prelude 同居)。
|
|
15
|
+
# 非 basic_auth 時は従来どおり HostRedirectFunction #}
|
|
16
|
+
# {% set bare_viewer_fn = "BasicAuthFunction" if basic_auth else "HostRedirectFunction" %}
|
|
14
17
|
# {% if has_token_kvs %}
|
|
15
18
|
TokenKvs:
|
|
16
19
|
Type: AWS::CloudFront::KeyValueStore
|
|
17
20
|
Properties:
|
|
18
21
|
Name: "{{ slug }}-token-kvs"
|
|
19
|
-
Comment: "KVS for SPA token secret"
|
|
22
|
+
Comment: "KVS for SPA token secret / basic auth credential"
|
|
20
23
|
# {% endif %}
|
|
21
24
|
|
|
22
25
|
# {% for route in routes %}
|
|
@@ -40,7 +43,7 @@ Resources:
|
|
|
40
43
|
FunctionConfig:
|
|
41
44
|
Comment: "CloudFront function for {{ route.name }}"
|
|
42
45
|
Runtime: cloudfront-js-2.0
|
|
43
|
-
# {% if route.require_token %}
|
|
46
|
+
# {% if route.require_token or basic_auth %}
|
|
44
47
|
KeyValueStoreAssociations:
|
|
45
48
|
- KeyValueStoreARN:
|
|
46
49
|
Fn::GetAtt: TokenKvs.Arn
|
|
@@ -69,6 +72,11 @@ Resources:
|
|
|
69
72
|
FunctionConfig:
|
|
70
73
|
Comment: "Strip deploy hash prefix for {{ route.name }}"
|
|
71
74
|
Runtime: cloudfront-js-2.0
|
|
75
|
+
# {% if basic_auth %}
|
|
76
|
+
KeyValueStoreAssociations:
|
|
77
|
+
- KeyValueStoreARN:
|
|
78
|
+
Fn::GetAtt: TokenKvs.Arn
|
|
79
|
+
# {% endif %}
|
|
72
80
|
# {% endif %}
|
|
73
81
|
# {% endfor %}
|
|
74
82
|
|
|
@@ -83,13 +91,19 @@ Resources:
|
|
|
83
91
|
FunctionConfig:
|
|
84
92
|
Comment: "Add X-Forwarded-Host for API routes"
|
|
85
93
|
Runtime: cloudfront-js-2.0
|
|
94
|
+
# {% if basic_auth %}
|
|
95
|
+
KeyValueStoreAssociations:
|
|
96
|
+
- KeyValueStoreARN:
|
|
97
|
+
Fn::GetAtt: TokenKvs.Arn
|
|
98
|
+
# {% endif %}
|
|
86
99
|
# {% endif %}
|
|
87
100
|
|
|
88
|
-
# {% if has_redirect_from %}
|
|
101
|
+
# {% if has_redirect_from and not basic_auth %}
|
|
89
102
|
# 非 canonical host (redirect_from ドメイン) を canonical domain へ 301 する
|
|
90
103
|
# viewer-request Function。既存 viewer-request Function を持たない behavior
|
|
91
104
|
# (プレーン S3 route / managed asset) にのみ association する。既存 Function を
|
|
92
105
|
# 持つ behavior には各 Function コード側に同等の redirect prelude を注入済み。
|
|
106
|
+
# basic_auth 時は BasicAuthFunction に redirect prelude が同居するため作らない。
|
|
93
107
|
HostRedirectFunction:
|
|
94
108
|
Type: AWS::CloudFront::Function
|
|
95
109
|
Properties:
|
|
@@ -102,6 +116,26 @@ Resources:
|
|
|
102
116
|
Runtime: cloudfront-js-2.0
|
|
103
117
|
# {% endif %}
|
|
104
118
|
|
|
119
|
+
# {% if basic_auth %}
|
|
120
|
+
# distribution 全体の Basic 認証。既存 viewer-request Function を持たない
|
|
121
|
+
# behavior (プレーン S3 route / managed asset) にのみ association する。既存
|
|
122
|
+
# Function を持つ behavior には各 Function コード側に同等の prelude を注入済み。
|
|
123
|
+
# redirect_from 有効時は host redirect prelude もこの Function に同居する。
|
|
124
|
+
BasicAuthFunction:
|
|
125
|
+
Type: AWS::CloudFront::Function
|
|
126
|
+
Properties:
|
|
127
|
+
Name: "{{ slug }}-basic-auth"
|
|
128
|
+
AutoPublish: true
|
|
129
|
+
FunctionCode: |
|
|
130
|
+
{{ basic_auth_function_code }}
|
|
131
|
+
FunctionConfig:
|
|
132
|
+
Comment: "Basic auth gate for {{ slug }}"
|
|
133
|
+
Runtime: cloudfront-js-2.0
|
|
134
|
+
KeyValueStoreAssociations:
|
|
135
|
+
- KeyValueStoreARN:
|
|
136
|
+
Fn::GetAtt: TokenKvs.Arn
|
|
137
|
+
# {% endif %}
|
|
138
|
+
|
|
105
139
|
CloudFrontDistribution:
|
|
106
140
|
Type: AWS::CloudFront::Distribution
|
|
107
141
|
DependsOn:
|
|
@@ -120,9 +154,12 @@ Resources:
|
|
|
120
154
|
# {% if has_lambda_route %}
|
|
121
155
|
- ApiHostFunction
|
|
122
156
|
# {% endif %}
|
|
123
|
-
# {% if has_redirect_from %}
|
|
157
|
+
# {% if has_redirect_from and not basic_auth %}
|
|
124
158
|
- HostRedirectFunction
|
|
125
159
|
# {% endif %}
|
|
160
|
+
# {% if basic_auth %}
|
|
161
|
+
- BasicAuthFunction
|
|
162
|
+
# {% endif %}
|
|
126
163
|
Properties:
|
|
127
164
|
DistributionConfig:
|
|
128
165
|
# {% if domain %}
|
|
@@ -198,11 +235,11 @@ Resources:
|
|
|
198
235
|
- EventType: viewer-request
|
|
199
236
|
FunctionARN:
|
|
200
237
|
Fn::GetAtt: UrlFallbackFunction{{ default_route.yaml_key }}.FunctionMetadata.FunctionARN
|
|
201
|
-
# {% elif has_redirect_from %}
|
|
238
|
+
# {% elif basic_auth or has_redirect_from %}
|
|
202
239
|
FunctionAssociations:
|
|
203
240
|
- EventType: viewer-request
|
|
204
241
|
FunctionARN:
|
|
205
|
-
Fn::GetAtt:
|
|
242
|
+
Fn::GetAtt: {{ bare_viewer_fn }}.FunctionMetadata.FunctionARN
|
|
206
243
|
# {% endif %}
|
|
207
244
|
# {% if default_route.versioning %}
|
|
208
245
|
ResponseHeadersPolicyId:
|
|
@@ -232,11 +269,11 @@ Resources:
|
|
|
232
269
|
FunctionARN:
|
|
233
270
|
Fn::GetAtt: DeployHashStripFunction{{ route.yaml_key }}.FunctionMetadata.FunctionARN
|
|
234
271
|
# {% endif %}
|
|
235
|
-
# {% if not route.is_spa and not route.is_deploy_hash and has_redirect_from %}
|
|
272
|
+
# {% if not route.is_spa and not route.is_deploy_hash and (basic_auth or has_redirect_from) %}
|
|
236
273
|
FunctionAssociations:
|
|
237
274
|
- EventType: viewer-request
|
|
238
275
|
FunctionARN:
|
|
239
|
-
Fn::GetAtt:
|
|
276
|
+
Fn::GetAtt: {{ bare_viewer_fn }}.FunctionMetadata.FunctionARN
|
|
240
277
|
# {% endif %}
|
|
241
278
|
# {% if route.versioning %}
|
|
242
279
|
ResponseHeadersPolicyId:
|
|
@@ -271,11 +308,11 @@ Resources:
|
|
|
271
308
|
TargetOriginId: "{{ resource_prefix }}pocket-managed"
|
|
272
309
|
ViewerProtocolPolicy: "redirect-to-https"
|
|
273
310
|
PathPattern: "/{{ filename }}"
|
|
274
|
-
# {% if has_redirect_from %}
|
|
311
|
+
# {% if basic_auth or has_redirect_from %}
|
|
275
312
|
FunctionAssociations:
|
|
276
313
|
- EventType: viewer-request
|
|
277
314
|
FunctionARN:
|
|
278
|
-
Fn::GetAtt:
|
|
315
|
+
Fn::GetAtt: {{ bare_viewer_fn }}.FunctionMetadata.FunctionARN
|
|
279
316
|
# {% endif %}
|
|
280
317
|
# {% endfor %}
|
|
281
318
|
# {% endif %}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "magic-pocket-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.19.0"
|
|
4
4
|
description = "CLI and deploy tools for magic-pocket."
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"magic-pocket>=0.
|
|
7
|
+
"magic-pocket>=0.19.0",
|
|
8
8
|
"click>=8.1.7",
|
|
9
9
|
"jinja2>=3.1.3",
|
|
10
10
|
"python-on-whales>=0.68.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/__init__.py
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/codebuild.py
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/depot.py
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/builders/docker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/lambdahandler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/resources/aws/stack_backed.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/cloudformation/vpc.yaml
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/django-dotenv.env
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/django-settings.py
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/pocket.Dockerfile
RENAMED
|
File without changes
|
{magic_pocket_cli-0.18.1 → magic_pocket_cli-0.19.0}/pocket_cli/templates/init/pocket_simple.toml
RENAMED
|
File without changes
|