@mriekki/project-forge 4.2.0 → 4.4.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.
- package/assets/components.json +3 -3
- package/assets/deployment/distribution.json +5 -0
- package/assets/generated/ASSEMBLY.json +37 -12
- package/assets/generated/core/core/process/DEPLOYMENT_ENABLEMENT.md +25 -1
- package/assets/generated/core/core/skills/deploy/SKILL.md +15 -3
- package/assets/generated/core/core/skills/deployment-readiness/SKILL.md +45 -1
- package/assets/generated/core/core/skills/setup/SKILL.md +21 -1
- package/assets/generated/deployment/docs/PROJECT_TOPOLOGY_BINDING.md +44 -0
- package/assets/generated/deployment/src/project_forge_deployment/app_cli.py +72 -21
- package/assets/generated/deployment/src/project_forge_deployment/app_deployment.py +194 -0
- package/assets/generated/deployment/src/project_forge_deployment/entrypoint.py +4 -0
- package/assets/generated/deployment/src/project_forge_deployment/environment_cli.py +60 -1
- package/assets/generated/deployment/src/project_forge_deployment/environment_isolation.py +438 -0
- package/assets/generated/deployment/src/project_forge_deployment/environment_probe.py +57 -1
- package/assets/generated/deployment/src/project_forge_deployment/environment_setup.py +72 -26
- package/assets/generated/deployment/src/project_forge_deployment/project_topology.py +218 -0
- package/assets/generated/deployment/src/project_forge_deployment/topology_cli.py +85 -0
- package/package.json +1 -1
package/assets/components.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "@mriekki/project-forge",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.4.0",
|
|
5
5
|
"defaultProfile": "greenfield-project",
|
|
6
6
|
"profiles": {
|
|
7
7
|
"greenfield-project": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"components": {
|
|
15
15
|
"core": {
|
|
16
16
|
"repository": "mriekki/project-forge-core",
|
|
17
|
-
"commit": "
|
|
17
|
+
"commit": "45139179c3d10ebd89702ac3aedec231364d8a34",
|
|
18
18
|
"version": "4.0.0",
|
|
19
19
|
"distribution": "greenfield-workspace",
|
|
20
20
|
"descriptor": "assets/core/distribution.json",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"deployment": {
|
|
25
25
|
"repository": "mriekki/project-forge-deployment-kit",
|
|
26
|
-
"commit": "
|
|
26
|
+
"commit": "eb157c8ae2c638ae1cd08bf27446d430835adc80",
|
|
27
27
|
"distribution": "greenfield-project",
|
|
28
28
|
"descriptor": "assets/deployment/distribution.json",
|
|
29
29
|
"sourceRoot": "assets/generated/deployment",
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
{"source": "src/project_forge_deployment/__init__.py", "destination": "tools/project-forge-deployment/project_forge_deployment/__init__.py"},
|
|
8
8
|
{"source": "src/project_forge_deployment/__main__.py", "destination": "tools/project-forge-deployment/project_forge_deployment/__main__.py"},
|
|
9
9
|
{"source": "src/project_forge_deployment/app_cli.py", "destination": "tools/project-forge-deployment/project_forge_deployment/app_cli.py"},
|
|
10
|
+
{"source": "src/project_forge_deployment/app_deployment.py", "destination": "tools/project-forge-deployment/project_forge_deployment/app_deployment.py"},
|
|
10
11
|
{"source": "src/project_forge_deployment/app_runtime.py", "destination": "tools/project-forge-deployment/project_forge_deployment/app_runtime.py"},
|
|
11
12
|
{"source": "src/project_forge_deployment/app_runtime_remote.py", "destination": "tools/project-forge-deployment/project_forge_deployment/app_runtime_remote.py"},
|
|
12
13
|
{"source": "src/project_forge_deployment/app_runtime_workstation.py", "destination": "tools/project-forge-deployment/project_forge_deployment/app_runtime_workstation.py"},
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
{"source": "src/project_forge_deployment/doctor.py", "destination": "tools/project-forge-deployment/project_forge_deployment/doctor.py"},
|
|
18
19
|
{"source": "src/project_forge_deployment/entrypoint.py", "destination": "tools/project-forge-deployment/project_forge_deployment/entrypoint.py"},
|
|
19
20
|
{"source": "src/project_forge_deployment/environment_cli.py", "destination": "tools/project-forge-deployment/project_forge_deployment/environment_cli.py"},
|
|
21
|
+
{"source": "src/project_forge_deployment/environment_isolation.py", "destination": "tools/project-forge-deployment/project_forge_deployment/environment_isolation.py"},
|
|
20
22
|
{"source": "src/project_forge_deployment/environment_probe.py", "destination": "tools/project-forge-deployment/project_forge_deployment/environment_probe.py"},
|
|
21
23
|
{"source": "src/project_forge_deployment/environment_setup.py", "destination": "tools/project-forge-deployment/project_forge_deployment/environment_setup.py"},
|
|
22
24
|
{"source": "src/project_forge_deployment/errors.py", "destination": "tools/project-forge-deployment/project_forge_deployment/errors.py"},
|
|
@@ -31,6 +33,7 @@
|
|
|
31
33
|
{"source": "src/project_forge_deployment/profile_migration.py", "destination": "tools/project-forge-deployment/project_forge_deployment/profile_migration.py"},
|
|
32
34
|
{"source": "src/project_forge_deployment/profile_repository.py", "destination": "tools/project-forge-deployment/project_forge_deployment/profile_repository.py"},
|
|
33
35
|
{"source": "src/project_forge_deployment/profiles.py", "destination": "tools/project-forge-deployment/project_forge_deployment/profiles.py"},
|
|
36
|
+
{"source": "src/project_forge_deployment/project_topology.py", "destination": "tools/project-forge-deployment/project_forge_deployment/project_topology.py"},
|
|
34
37
|
{"source": "src/project_forge_deployment/proof_receipt.py", "destination": "tools/project-forge-deployment/project_forge_deployment/proof_receipt.py"},
|
|
35
38
|
{"source": "src/project_forge_deployment/registry_access.py", "destination": "tools/project-forge-deployment/project_forge_deployment/registry_access.py"},
|
|
36
39
|
{"source": "src/project_forge_deployment/registry_cli.py", "destination": "tools/project-forge-deployment/project_forge_deployment/registry_cli.py"},
|
|
@@ -45,10 +48,12 @@
|
|
|
45
48
|
{"source": "src/project_forge_deployment/teardown.py", "destination": "tools/project-forge-deployment/project_forge_deployment/teardown.py"},
|
|
46
49
|
{"source": "src/project_forge_deployment/teardown_cli.py", "destination": "tools/project-forge-deployment/project_forge_deployment/teardown_cli.py"},
|
|
47
50
|
{"source": "src/project_forge_deployment/teardown_remote.py", "destination": "tools/project-forge-deployment/project_forge_deployment/teardown_remote.py"},
|
|
51
|
+
{"source": "src/project_forge_deployment/topology_cli.py", "destination": "tools/project-forge-deployment/project_forge_deployment/topology_cli.py"},
|
|
48
52
|
{"source": "src/project_forge_deployment/trust.py", "destination": "tools/project-forge-deployment/project_forge_deployment/trust.py"},
|
|
49
53
|
{"source": "docs/DEVELOPER_ENVIRONMENTS.md", "destination": "docs/project-forge/DEVELOPER_ENVIRONMENTS.md"},
|
|
50
54
|
{"source": "docs/WORKSPACE_INSTANCES.md", "destination": "docs/project-forge/WORKSPACE_INSTANCES.md"},
|
|
51
55
|
{"source": "docs/ENVIRONMENT_PROOF.md", "destination": "docs/project-forge/ENVIRONMENT_PROOF.md"},
|
|
56
|
+
{"source": "docs/PROJECT_TOPOLOGY_BINDING.md", "destination": "docs/project-forge/PROJECT_TOPOLOGY_BINDING.md"},
|
|
52
57
|
{"source": "docs/images/developer-environment-journey.svg", "destination": "docs/project-forge/images/developer-environment-journey.svg"},
|
|
53
58
|
{"source": "docs/images/personal-environment-architecture.svg", "destination": "docs/project-forge/images/personal-environment-architecture.svg"},
|
|
54
59
|
{"source": "docs/images/project-environment-model.svg", "destination": "docs/project-forge/images/project-environment-model.svg"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "@mriekki/project-forge",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.4.0",
|
|
5
5
|
"components": {
|
|
6
6
|
"core": {
|
|
7
7
|
"repository": "mriekki/project-forge-core",
|
|
8
|
-
"commit": "
|
|
8
|
+
"commit": "45139179c3d10ebd89702ac3aedec231364d8a34",
|
|
9
9
|
"version": "4.0.0",
|
|
10
10
|
"distribution": "greenfield-workspace",
|
|
11
11
|
"files": [
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
{
|
|
53
53
|
"source": "core/skills/setup/SKILL.md",
|
|
54
54
|
"destination": ".github/skills/setup/SKILL.md",
|
|
55
|
-
"sha256": "
|
|
55
|
+
"sha256": "0ba13a009347742ede2c6e6121a21f29640a05864a994c7a51b4c992c0b2c619"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"source": "core/skills/build/SKILL.md",
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
{
|
|
118
118
|
"source": "core/skills/deployment-readiness/SKILL.md",
|
|
119
119
|
"destination": ".github/skills/deployment-readiness/SKILL.md",
|
|
120
|
-
"sha256": "
|
|
120
|
+
"sha256": "33be75e856b1b16378bb2a456d8418f8ae0b03edee75fb826d8f7ef3824d2f6a"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"source": "core/skills/deploy/SKILL.md",
|
|
124
124
|
"destination": ".github/skills/deploy/SKILL.md",
|
|
125
|
-
"sha256": "
|
|
125
|
+
"sha256": "21b8209bc756ef2981f9e44f19ee80e79c1c5c7d5be4c03c9b528fdadd7b8eca"
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
"source": "core/skills/tear-down/SKILL.md",
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
{
|
|
173
173
|
"source": "core/process/DEPLOYMENT_ENABLEMENT.md",
|
|
174
174
|
"destination": "docs/process/DEPLOYMENT_ENABLEMENT.md",
|
|
175
|
-
"sha256": "
|
|
175
|
+
"sha256": "f45b84f64975f5f90f639ed1f4f8709d0153d48d109198764c0ec13218956188"
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
178
|
"source": "core/process/HUMAN_GATES.md",
|
|
@@ -328,7 +328,7 @@
|
|
|
328
328
|
},
|
|
329
329
|
"deployment": {
|
|
330
330
|
"repository": "mriekki/project-forge-deployment-kit",
|
|
331
|
-
"commit": "
|
|
331
|
+
"commit": "eb157c8ae2c638ae1cd08bf27446d430835adc80",
|
|
332
332
|
"distribution": "greenfield-project",
|
|
333
333
|
"files": [
|
|
334
334
|
{
|
|
@@ -349,7 +349,12 @@
|
|
|
349
349
|
{
|
|
350
350
|
"source": "src/project_forge_deployment/app_cli.py",
|
|
351
351
|
"destination": "tools/project-forge-deployment/project_forge_deployment/app_cli.py",
|
|
352
|
-
"sha256": "
|
|
352
|
+
"sha256": "9bf8eb7337c5b506311bf718de71b9a2c9ac445eb94cb7dfdeb63a09e5f0f899"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"source": "src/project_forge_deployment/app_deployment.py",
|
|
356
|
+
"destination": "tools/project-forge-deployment/project_forge_deployment/app_deployment.py",
|
|
357
|
+
"sha256": "e58158e48c9fbd51b51f7af90f2dd178987ad3936e44507523cfc41b96fcd9f9"
|
|
353
358
|
},
|
|
354
359
|
{
|
|
355
360
|
"source": "src/project_forge_deployment/app_runtime.py",
|
|
@@ -394,22 +399,27 @@
|
|
|
394
399
|
{
|
|
395
400
|
"source": "src/project_forge_deployment/entrypoint.py",
|
|
396
401
|
"destination": "tools/project-forge-deployment/project_forge_deployment/entrypoint.py",
|
|
397
|
-
"sha256": "
|
|
402
|
+
"sha256": "341e4682a050e9eea8c6ecf0e8728efacc57f06144d9eceb12ac37cf8fb2a3b4"
|
|
398
403
|
},
|
|
399
404
|
{
|
|
400
405
|
"source": "src/project_forge_deployment/environment_cli.py",
|
|
401
406
|
"destination": "tools/project-forge-deployment/project_forge_deployment/environment_cli.py",
|
|
402
|
-
"sha256": "
|
|
407
|
+
"sha256": "ff4883a491dc4b4fab4e4c2afbb2eb3f65ddce6ae7ff22df7ab355ded5cc4f6b"
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"source": "src/project_forge_deployment/environment_isolation.py",
|
|
411
|
+
"destination": "tools/project-forge-deployment/project_forge_deployment/environment_isolation.py",
|
|
412
|
+
"sha256": "aa2f380c7cbf474084375460c9d9168390c608a6566559eab778764ad5cf094d"
|
|
403
413
|
},
|
|
404
414
|
{
|
|
405
415
|
"source": "src/project_forge_deployment/environment_probe.py",
|
|
406
416
|
"destination": "tools/project-forge-deployment/project_forge_deployment/environment_probe.py",
|
|
407
|
-
"sha256": "
|
|
417
|
+
"sha256": "0a7b7a939fa38172abf85a036e2e8e9e97fa2c890f63a2e4d9304b4d62ebfa2d"
|
|
408
418
|
},
|
|
409
419
|
{
|
|
410
420
|
"source": "src/project_forge_deployment/environment_setup.py",
|
|
411
421
|
"destination": "tools/project-forge-deployment/project_forge_deployment/environment_setup.py",
|
|
412
|
-
"sha256": "
|
|
422
|
+
"sha256": "47ce6af4ab3b03c441725ec8cc1b356212ef7a1706635fe191affd959b09a5f5"
|
|
413
423
|
},
|
|
414
424
|
{
|
|
415
425
|
"source": "src/project_forge_deployment/errors.py",
|
|
@@ -471,6 +481,11 @@
|
|
|
471
481
|
"destination": "tools/project-forge-deployment/project_forge_deployment/profiles.py",
|
|
472
482
|
"sha256": "c8fb1c378af9d39d28f46b300064bec967e2a6f7a13e22d089fc00413c42fd9d"
|
|
473
483
|
},
|
|
484
|
+
{
|
|
485
|
+
"source": "src/project_forge_deployment/project_topology.py",
|
|
486
|
+
"destination": "tools/project-forge-deployment/project_forge_deployment/project_topology.py",
|
|
487
|
+
"sha256": "72e810d5c6438529195069a5640c74e2774816c16bc6b0f5beff152710240bf7"
|
|
488
|
+
},
|
|
474
489
|
{
|
|
475
490
|
"source": "src/project_forge_deployment/proof_receipt.py",
|
|
476
491
|
"destination": "tools/project-forge-deployment/project_forge_deployment/proof_receipt.py",
|
|
@@ -541,6 +556,11 @@
|
|
|
541
556
|
"destination": "tools/project-forge-deployment/project_forge_deployment/teardown_remote.py",
|
|
542
557
|
"sha256": "ad764f5a67c43f81b4973dd5639b2c28b23ae883a85e5ae29efc14dad506e88e"
|
|
543
558
|
},
|
|
559
|
+
{
|
|
560
|
+
"source": "src/project_forge_deployment/topology_cli.py",
|
|
561
|
+
"destination": "tools/project-forge-deployment/project_forge_deployment/topology_cli.py",
|
|
562
|
+
"sha256": "83523efa8c175dfc0235844fcfe3b51a4af3e807e83165cca63c81f675030f8c"
|
|
563
|
+
},
|
|
544
564
|
{
|
|
545
565
|
"source": "src/project_forge_deployment/trust.py",
|
|
546
566
|
"destination": "tools/project-forge-deployment/project_forge_deployment/trust.py",
|
|
@@ -561,6 +581,11 @@
|
|
|
561
581
|
"destination": "docs/project-forge/ENVIRONMENT_PROOF.md",
|
|
562
582
|
"sha256": "2ce7225ad6166a4ee30f51ea67ec077de0c29ce3a5c39b4ff57bf11cbe25e927"
|
|
563
583
|
},
|
|
584
|
+
{
|
|
585
|
+
"source": "docs/PROJECT_TOPOLOGY_BINDING.md",
|
|
586
|
+
"destination": "docs/project-forge/PROJECT_TOPOLOGY_BINDING.md",
|
|
587
|
+
"sha256": "50988ac1d797494bcb2d5dd6cece04f6313fb30179ca3132191dea75bcd759cd"
|
|
588
|
+
},
|
|
564
589
|
{
|
|
565
590
|
"source": "docs/images/developer-environment-journey.svg",
|
|
566
591
|
"destination": "docs/project-forge/images/developer-environment-journey.svg",
|
|
@@ -78,6 +78,24 @@ If existing configuration is present, show known facts for confirmation. If part
|
|
|
78
78
|
|
|
79
79
|
Remote probing requires explicit read-only authorization. Address discovery never substitutes for cryptographic host identity. Unknown/changed SSH identity fails closed.
|
|
80
80
|
|
|
81
|
+
### Real application isolation readiness
|
|
82
|
+
|
|
83
|
+
For supported remote application deployment, readiness should use the repository-distributed Deployment Kit launcher rather than infer collision safety from prose:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
tools/project-forge-deployment/project-forge-deploy.py app isolation ... --require-clear --json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The read-only check should be built from the exact known application footprint: target binding, owner repository, exact logical environment, resolved Production classification, app slug, container name, runtime port, persistence mode, optional SQLite database file, and intended route hostnames when applicable.
|
|
90
|
+
|
|
91
|
+
The deterministic result may prove the current managed application footprint is non-colliding across ownership, runtime/container identity, route hostnames/upstream ownership, SQLite identity, persistence root, and per-app/per-environment lock identity. It may also report colocated sibling environments and a shared physical failure domain.
|
|
92
|
+
|
|
93
|
+
A clear result is pre-deploy evidence only. It does not authorize application, route, persistence, migration, Production, or destructive writes. A blocked result means readiness must stop before the real application write gate and surface the structured conflict evidence.
|
|
94
|
+
|
|
95
|
+
If installed package tooling lacks the required isolation capability, require a Project Forge capability/update path rather than reconstructing equivalent checks from model knowledge.
|
|
96
|
+
|
|
97
|
+
When available, retain the isolation evidence fingerprint for human review. `/deploy` must still use the deterministic planner and current-state revalidation before mutation; a readiness fingerprint is not a durable write authorization.
|
|
98
|
+
|
|
81
99
|
## Deferred readiness
|
|
82
100
|
|
|
83
101
|
A deferred placement is intentional configuration state:
|
|
@@ -108,6 +126,8 @@ failure domain. This may fit Project cost/learning goals, but it does not
|
|
|
108
126
|
demonstrate host-level Production isolation.
|
|
109
127
|
```
|
|
110
128
|
|
|
129
|
+
A clear application isolation preflight confirms only the currently requested Deployment Kit-managed footprint is non-colliding. It does not demonstrate host-level Production isolation.
|
|
130
|
+
|
|
111
131
|
Production backup/recovery/security/deploy/destructive gates remain stronger regardless of colocation.
|
|
112
132
|
|
|
113
133
|
## Readiness cadence
|
|
@@ -118,6 +138,7 @@ select environment
|
|
|
118
138
|
→ inspect placement-relevant local state
|
|
119
139
|
→ show/confirm known facts
|
|
120
140
|
→ authorize relevant read-only verification
|
|
141
|
+
→ run deterministic application isolation preflight when supported
|
|
121
142
|
→ repair only missing prerequisites under explicit write gates
|
|
122
143
|
→ ENVIRONMENT READY TO DEPLOY
|
|
123
144
|
→ /deploy <environment>
|
|
@@ -133,6 +154,8 @@ Readiness does **not** hide application deployment inside setup.
|
|
|
133
154
|
|
|
134
155
|
Application runtime deployment, release-specific migration, route/port publication, live health/readiness, smoke validation, and release-specific evidence belong to `/deploy` when the installed adapter defines them.
|
|
135
156
|
|
|
157
|
+
The application isolation preflight is a remote read-only inspection and does not itself authorize any later write.
|
|
158
|
+
|
|
136
159
|
## Pre-deploy versus post-deploy evidence
|
|
137
160
|
|
|
138
161
|
Readiness proves only facts that can exist before deployment, such as:
|
|
@@ -142,6 +165,7 @@ Readiness proves only facts that can exist before deployment, such as:
|
|
|
142
165
|
- local Docker readiness or verified remote target/identity depending on placement;
|
|
143
166
|
- target OS/runtime when applicable;
|
|
144
167
|
- artifact identity/access;
|
|
168
|
+
- deterministic application isolation/collision evidence when supported;
|
|
145
169
|
- route/port ownership availability;
|
|
146
170
|
- persistence/backup/migration prerequisites;
|
|
147
171
|
- deployment lock/recovery capability;
|
|
@@ -163,4 +187,4 @@ Once ready:
|
|
|
163
187
|
/deploy <environment>
|
|
164
188
|
```
|
|
165
189
|
|
|
166
|
-
`/deploy` verifies current topology/target/artifact evidence, presents the exact installed-tool authorization gate, delegates deterministic mechanics, and verifies placement-relevant live evidence.
|
|
190
|
+
`/deploy` verifies current topology/target/artifact evidence, presents the exact installed-tool authorization gate, delegates deterministic mechanics, requires current isolation evidence when the installed adapter defines it, and verifies placement-relevant live evidence.
|
|
@@ -44,7 +44,7 @@ Read only what is needed, including when present:
|
|
|
44
44
|
- `PROJECT_FORGE_BASELINE.json`;
|
|
45
45
|
- `DEPLOYMENT_BASELINE.json`;
|
|
46
46
|
- project topology and approved deployment/release requirements;
|
|
47
|
-
- `/deployment-readiness` evidence;
|
|
47
|
+
- `/deployment-readiness` evidence, including deterministic application isolation evidence when supported;
|
|
48
48
|
- fresh setup-time environment-proof evidence for this workstation;
|
|
49
49
|
- established application deployment facts.
|
|
50
50
|
|
|
@@ -60,6 +60,8 @@ When a fresh setup-time proof already demonstrated target access, platform readi
|
|
|
60
60
|
|
|
61
61
|
Proof does not establish the real application's image/release, persistence/migration contract, route/exposure, secrets, health contract, or release policy.
|
|
62
62
|
|
|
63
|
+
A prior readiness isolation fingerprint is review evidence only. It does not authorize deployment and does not replace the deterministic deployment planner's current isolation revalidation.
|
|
64
|
+
|
|
63
65
|
## 3. First real deployment asks only unresolved application questions
|
|
64
66
|
|
|
65
67
|
The first real `/deploy <environment>` after environment proof may need a small application-specific completion step. Ask only material unknowns not already answered by project evidence, such as:
|
|
@@ -102,6 +104,8 @@ exact image acquired/built locally
|
|
|
102
104
|
|
|
103
105
|
Do not copy a developer GitHub PAT/GHCR credential to the target as normal deployment behavior.
|
|
104
106
|
|
|
107
|
+
For installed Deployment Kit versions that expose real application isolation planning, require that capability rather than reconstructing collision checks from model knowledge. If the installed package lacks the capability required by current Core policy, stop with a Project Forge update/capability requirement before requesting the application write authorization.
|
|
108
|
+
|
|
105
109
|
### Managed service
|
|
106
110
|
|
|
107
111
|
Use only an installed repository/catalog provider adapter. If none exists, stop with `CATALOG GAP / PLANNED` rather than constructing provider commands from general knowledge.
|
|
@@ -137,6 +141,12 @@ optional backup/safety check
|
|
|
137
141
|
→ deployment evidence capture
|
|
138
142
|
```
|
|
139
143
|
|
|
144
|
+
For the standard remote Deployment Kit path, pass the intended application footprint needed by the installed planner's isolation contract, including exact target, owner repository, environment, Production classification, app slug, container name, runtime port, persistence mode, optional SQLite database file, and intended route hostnames when applicable.
|
|
145
|
+
|
|
146
|
+
When the deterministic application plan exposes reviewed isolation evidence (for example `isolationReview`), require a clear state and retain its evidence fingerprint for the human preview. A blocked plan is not deployable. Do not edit names/ports/routes/persistence identities automatically to make a blocked plan pass.
|
|
147
|
+
|
|
148
|
+
The deterministic deployment tool owns the final current-state recheck immediately before mutation. Core must not substitute a stale readiness fingerprint or prose-only reasoning for that revalidation.
|
|
149
|
+
|
|
140
150
|
Do not smuggle infrastructure provisioning, target/provider rebinding, destructive restore, or environment tear-down into the application plan.
|
|
141
151
|
|
|
142
152
|
## 7. Preserve exact authorization contracts
|
|
@@ -154,14 +164,16 @@ For Production-class environments also show `[PRODUCTION WRITE]` consequence vis
|
|
|
154
164
|
|
|
155
165
|
Resolve the exact phrase from the installed tool/version. Do not assume an example phrase when the installed contract differs.
|
|
156
166
|
|
|
157
|
-
Authorization applies only to the exact environment, resolved classification, placement/target/provider, artifact, reviewed plan, and evidence shown. Material changes require renewed review/authorization.
|
|
167
|
+
Authorization applies only to the exact environment, resolved classification, placement/target/provider, artifact, reviewed plan, current isolation evidence, and evidence shown. Material changes require renewed review/authorization.
|
|
158
168
|
|
|
159
169
|
## 8. Preview and execute only the approved contract
|
|
160
170
|
|
|
161
|
-
Before mutation, show concise non-secret evidence such as exact environment, purpose, placement, target/provider when applicable, proof freshness, immutable application artifact, persistence/migration, exposure/route, planned operations, and exact required authorization phrase.
|
|
171
|
+
Before mutation, show concise non-secret evidence such as exact environment, purpose, placement, target/provider when applicable, proof freshness, immutable application artifact, persistence/migration, exposure/route, application isolation state/fingerprint when exposed, shared failure-domain note when relevant, planned operations, and exact required authorization phrase.
|
|
162
172
|
|
|
163
173
|
After authorization, invoke only the repository-provided deterministic launcher. Never redirect to another environment/host/provider, weaken trust/exposure, force through lock contention, or invent recovery writes.
|
|
164
174
|
|
|
175
|
+
The deterministic launcher must revalidate current isolation immediately before real application mutation when the installed contract provides that capability. If current isolation changed or became blocked after review, stop and create/review a fresh plan rather than continuing under the old authorization.
|
|
176
|
+
|
|
165
177
|
Existing per-app/per-environment locks are normal concurrency protection when another workstation is deploying the same environment.
|
|
166
178
|
|
|
167
179
|
## 9. Validate live evidence
|
|
@@ -129,6 +129,43 @@ Before asking questions, inspect existing non-secret profile/target evidence. Cl
|
|
|
129
129
|
|
|
130
130
|
Only after explicit `[REMOTE READ ONLY]` authorization under the installed/repository contract may new remote checks occur. Never scan/select another host or weaken host-key verification merely to get a green result.
|
|
131
131
|
|
|
132
|
+
#### Real application isolation preflight
|
|
133
|
+
|
|
134
|
+
For a supported remote application deployment, prefer the repository-distributed launcher:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
tools/project-forge-deployment/project-forge-deploy.py
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Inspect installed help/version evidence before relying on a specific subcommand. When the installed contract exposes `app isolation`, use that deterministic read-only capability before declaring the application footprint ready. Do not reconstruct equivalent collision logic from model knowledge.
|
|
141
|
+
|
|
142
|
+
Build the check from exact project/topology/application evidence only:
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
app isolation <target>
|
|
146
|
+
--owner-repo <owner/repository>
|
|
147
|
+
--environment <exact logical environment>
|
|
148
|
+
--app-slug <application slug>
|
|
149
|
+
--container-name <managed container name>
|
|
150
|
+
--runtime-port <container-scoped runtime port>
|
|
151
|
+
--persistence-mode <none|directory>
|
|
152
|
+
[--database-file <SQLite file when applicable>]
|
|
153
|
+
[--route-hostname <intended hostname> ...]
|
|
154
|
+
[--production when resolved purpose/classification is Production]
|
|
155
|
+
--require-clear
|
|
156
|
+
--json
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Pass `--production` for custom Production names such as `prod-east`; never downgrade Production policy because the literal environment name differs.
|
|
160
|
+
|
|
161
|
+
The isolation check is remote read-only evidence. A clear result may establish that the requested Project/environment footprint does not collide with current Deployment Kit-managed application ownership, container identity, route hostnames/upstream ownership, SQLite identity, persistence root, or deployment-lock identity. It may also report a shared physical failure domain and sibling logical environments.
|
|
162
|
+
|
|
163
|
+
A blocked result or nonzero `--require-clear` outcome means the environment is **not ready to deploy**. Surface the structured collision codes/evidence and stop before any application write gate. Do not auto-rename the environment, container, route, database, target, or app merely to obtain a clear result.
|
|
164
|
+
|
|
165
|
+
If current installed tooling does not expose the required isolation capability, report an installed-capability / Project Forge update requirement. Do not silently fall back to prose-only collision reasoning.
|
|
166
|
+
|
|
167
|
+
Keep the returned isolation `evidenceSha256` with readiness evidence when available. It is review evidence, not a reusable write authorization; `/deploy` and the deterministic deployment tool must re-evaluate current state before mutation.
|
|
168
|
+
|
|
132
169
|
### C. Managed-service placement
|
|
133
170
|
|
|
134
171
|
Use only a repository/catalog-provided provider adapter. If none exists, report:
|
|
@@ -155,6 +192,8 @@ Do not mark workspace readiness failed. Route to `/setup <environment>` or `/set
|
|
|
155
192
|
|
|
156
193
|
Multiple logical environments may share physical failure domains, but they remain independently targetable and independently authorized. If environments share physical failure, state it explicitly.
|
|
157
194
|
|
|
195
|
+
A clear application isolation preflight means the current Deployment Kit-managed footprint is non-colliding; it does **not** demonstrate host-level Production isolation.
|
|
196
|
+
|
|
158
197
|
Colocation does not demonstrate host-level Production isolation. Never infer readiness for one logical environment from another merely because they share hardware.
|
|
159
198
|
|
|
160
199
|
## 5. State-driven cadence
|
|
@@ -166,6 +205,7 @@ select exact project-defined environment
|
|
|
166
205
|
→ read current topology
|
|
167
206
|
→ reuse fresh environment-proof evidence when valid
|
|
168
207
|
→ rediscover placement-relevant local state
|
|
208
|
+
→ verify current application isolation when the installed adapter supports it
|
|
169
209
|
→ verify/repair only missing prerequisites under exact gates
|
|
170
210
|
→ ENVIRONMENT READY TO DEPLOY
|
|
171
211
|
→ /deploy <environment>
|
|
@@ -195,11 +235,13 @@ A missing prerequisite is not authorization to change it. Use the repository/too
|
|
|
195
235
|
|
|
196
236
|
Do not hide the real application deployment inside readiness. Readiness may rely on the disposable setup-time proof, but it must not start/replace the real project runtime, register the final application route, perform release-specific migration, or claim project-release smoke validation.
|
|
197
237
|
|
|
238
|
+
The application isolation preflight itself is read-only and does not authorize later deployment, route, persistence, migration, Production, or destructive writes.
|
|
239
|
+
|
|
198
240
|
## 8. Pre-deploy versus post-deploy evidence
|
|
199
241
|
|
|
200
242
|
Readiness asks whether `/deploy <name>` can safely perform the real application deployment now.
|
|
201
243
|
|
|
202
|
-
Pre-deploy evidence may include topology, adapter availability, binding, local/remote identity and access, target platform, fresh proof evidence, artifact policy, route/port availability, persistence/backup/migration prerequisites, lock/recovery capability, and Production-specific safeguards.
|
|
244
|
+
Pre-deploy evidence may include topology, adapter availability, binding, local/remote identity and access, target platform, fresh proof evidence, artifact policy, deterministic application isolation/collision evidence, route/port availability, persistence/backup/migration prerequisites, lock/recovery capability, and Production-specific safeguards.
|
|
203
245
|
|
|
204
246
|
Do not require first-deployment live route, deployed-release identity, application health, or smoke evidence before the application has ever been deployed. Those are post-deploy validation evidence owned by `/deploy`.
|
|
205
247
|
|
|
@@ -221,6 +263,8 @@ Purpose: <purpose>
|
|
|
221
263
|
Placement: <...>
|
|
222
264
|
Binding: VERIFIED / LOCAL / provider-specific
|
|
223
265
|
This-workstation environment proof: PROVEN / NOT REQUIRED / NOT AVAILABLE
|
|
266
|
+
Application isolation: CLEAR / NOT APPLICABLE
|
|
267
|
+
Isolation evidence: <evidenceSha256 when exposed by installed tooling>
|
|
224
268
|
Platform prerequisites: READY
|
|
225
269
|
Application-specific prerequisites: READY / <remaining items>
|
|
226
270
|
Security blockers: NONE
|
|
@@ -228,6 +228,26 @@ Normal commands then use that exact name, for example:
|
|
|
228
228
|
|
|
229
229
|
Do not create an environment whose required placement/adapter is unsupported; report the concrete `CATALOG GAP` or deferred state instead.
|
|
230
230
|
|
|
231
|
+
### Complete a deferred remote target binding before remote setup
|
|
232
|
+
|
|
233
|
+
When the selected existing environment already declares `placement: remote-target` and `adapter: remote-ssh` but has `bindingState: deferred`, treat target selection as a guided Project-configuration subflow rather than a terminal setup blocker.
|
|
234
|
+
|
|
235
|
+
1. Inspect/sync the developer's reusable non-secret target definitions through installed Deployment Kit personal-profile operations. Prefer `project-forge-deploy environment profile sync --apply --json` when available. Use the returned structured target/import evidence plus current local target profiles; do not invent a workstation registry.
|
|
236
|
+
2. Present compatible existing logical targets as a host-native **single-select** choice. Include `Other / define another target` and `Cancel / keep deferred`. Never silently choose a target, and never preselect or infer a Production target merely from an environment name.
|
|
237
|
+
3. If the developer chooses another target, use the supported Deployment Kit target-profile flow to define that non-secret logical target. Keep SSH identity/trust onboarding separate and never ask for private keys, passwords, or tokens in chat.
|
|
238
|
+
4. Before any Project write, preview the exact binding with the deterministic topology command when available:
|
|
239
|
+
|
|
240
|
+
```text
|
|
241
|
+
project-forge-deploy topology plan-binding <environment> --target-profile <target> --root . --json
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Show the reviewed before/after environment record, selected target, Production classification, changed fields, and required authorization. The supported deferred-binding operation may change only `bindingState` and `targetProfile`; it must not rewrite placement, isolation, exposure, adapter, failure domain, purpose, or role.
|
|
245
|
+
5. Require the bounded Project-configuration authorization reported by the plan. Production-class configuration uses its distinct Production topology-write authorization, but that authorization is **not** a Production proof or application-deployment authorization.
|
|
246
|
+
6. After approval, apply the reviewed plan through the deterministic command (for example `project-forge-deploy topology bind ... --yes --json` when the orchestration layer has just collected the exact required approval). Do not hand-edit `DEPLOYMENT_TOPOLOGY.json` in the skill. If installed Project Forge tooling does not expose the deterministic binding capability, route to the applicable Project Forge update/capability path instead of inventing JSON mutation logic.
|
|
247
|
+
7. Re-read `DEPLOYMENT_TOPOLOGY.json` after the write. Continue normal `/setup <environment>` using the persisted logical target and, when available, use structured `environment setup check`/`plan` evidence for access/platform/proof readiness.
|
|
248
|
+
|
|
249
|
+
A configured environment that already points at a different target is a **rebind**, not deferred binding completion. Stop for a separate explicit topology-change decision; do not reuse this subflow to move an existing environment silently. Bootstrap remains provenance and must not be rewritten to record the later binding.
|
|
250
|
+
|
|
231
251
|
## 7. `/setup remote` and `/setup <environment>` prepare remote-enabled capability
|
|
232
252
|
|
|
233
253
|
Remote setup proves that this workstation can later work with the configured non-Production or Production-class environment under its normal safety contract. It does **not** publish an artifact or deploy the real application.
|
|
@@ -373,4 +393,4 @@ Useful next actions include:
|
|
|
373
393
|
- `/deploy <environment>` — only after readiness and its own authorization contract;
|
|
374
394
|
- `/tear-down <scope>` — destructive cleanup under its separate gate.
|
|
375
395
|
|
|
376
|
-
Do not create a second top-level developer-environment-mode workflow. Local/remote workstation convergence belongs here.
|
|
396
|
+
Do not create a second top-level developer-environment-mode workflow. Local/remote workstation convergence belongs here.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Project topology target binding
|
|
2
|
+
|
|
3
|
+
Project Forge keeps reusable non-secret target definitions in the developer's personal profile while each Project owns its logical environment-to-target binding in `DEPLOYMENT_TOPOLOGY.json`.
|
|
4
|
+
|
|
5
|
+
For an existing environment whose durable intent is already `placement: remote-target`, `adapter: remote-ssh`, and `bindingState: deferred`, Deployment Kit can preview and persist one target binding without rewriting Bootstrap provenance or other topology fields.
|
|
6
|
+
|
|
7
|
+
## Preview
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
project-forge-deploy topology plan-binding <environment> \
|
|
11
|
+
--target-profile <logical-target> \
|
|
12
|
+
--root . \
|
|
13
|
+
--json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The preview:
|
|
17
|
+
|
|
18
|
+
- reads the current project-owned topology;
|
|
19
|
+
- requires the named environment to already be a remote-target/remote-ssh environment;
|
|
20
|
+
- loads the selected user-scoped target profile;
|
|
21
|
+
- checks declared target OS compatibility;
|
|
22
|
+
- shows the exact before/after environment record;
|
|
23
|
+
- changes only `bindingState` and `targetProfile`;
|
|
24
|
+
- records a topology hash so a later write fails if the file changed after preview;
|
|
25
|
+
- never deploys an application, runs a proof, or changes target SSH/profile state.
|
|
26
|
+
|
|
27
|
+
A configured environment bound to another target is not eligible for this command. Rebinding requires a separate explicit topology-change contract.
|
|
28
|
+
|
|
29
|
+
## Apply
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
project-forge-deploy topology bind <environment> \
|
|
33
|
+
--target-profile <logical-target> \
|
|
34
|
+
--root .
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The write requires the bounded phrase reported by the plan:
|
|
38
|
+
|
|
39
|
+
- `[PROJECT TOPOLOGY WRITE]` for non-Production environments;
|
|
40
|
+
- `[PROJECT PRODUCTION TOPOLOGY WRITE]` for Production-class environments.
|
|
41
|
+
|
|
42
|
+
Production classification comes from the existing topology role. The command never infers a Production target and this authorization is only for project configuration; it does **not** authorize Production proof or application deployment.
|
|
43
|
+
|
|
44
|
+
After a successful write, callers should re-read `DEPLOYMENT_TOPOLOGY.json` and continue normal environment setup/readiness from the selected logical target.
|
|
@@ -7,16 +7,19 @@ import json
|
|
|
7
7
|
import sys
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
+
from .app_deployment import (
|
|
11
|
+
app_isolation_check,
|
|
12
|
+
apply_app_deploy,
|
|
13
|
+
apply_app_deploy_from_workstation,
|
|
14
|
+
plan_app_deploy,
|
|
15
|
+
)
|
|
10
16
|
from .app_runtime import (
|
|
11
17
|
APP_DEPLOY_WRITE_PHRASE,
|
|
12
18
|
PRODUCTION_APP_DEPLOY_WRITE_PHRASE,
|
|
13
19
|
app_inventory,
|
|
14
|
-
apply_app_deploy,
|
|
15
20
|
deploy_write_phrase,
|
|
16
21
|
normalize_app_spec,
|
|
17
|
-
plan_app_deploy,
|
|
18
22
|
)
|
|
19
|
-
from .app_runtime_workstation import apply_app_deploy_from_workstation
|
|
20
23
|
from .errors import DeploymentKitError
|
|
21
24
|
from .sqlite_adapter import assert_app_spec_matches_persistence
|
|
22
25
|
|
|
@@ -53,6 +56,35 @@ def _confirm(args: argparse.Namespace, phrase: str, action: str) -> None:
|
|
|
53
56
|
raise DeploymentKitError(f"{action.capitalize()} was not authorized.")
|
|
54
57
|
|
|
55
58
|
|
|
59
|
+
def _add_isolation_footprint(parser: argparse.ArgumentParser) -> None:
|
|
60
|
+
parser.add_argument("name")
|
|
61
|
+
parser.add_argument("--owner-repo", required=True)
|
|
62
|
+
parser.add_argument("--environment", required=True)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--production",
|
|
65
|
+
action="store_true",
|
|
66
|
+
help="Classify this named environment as Production even when its name is not literally 'production'",
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument("--app-slug", required=True)
|
|
69
|
+
parser.add_argument("--container-name", required=True)
|
|
70
|
+
parser.add_argument("--runtime-port", type=int, required=True)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--persistence-mode",
|
|
73
|
+
choices=("none", "directory"),
|
|
74
|
+
required=True,
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--database-file",
|
|
78
|
+
help="Optional intended SQLite database file used only for read-only collision/isolation checks",
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--route-hostname",
|
|
82
|
+
action="append",
|
|
83
|
+
default=[],
|
|
84
|
+
help="Optional intended route hostname used only for read-only collision/isolation checks; repeat as needed",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
56
88
|
def build_parser() -> argparse.ArgumentParser:
|
|
57
89
|
parser = argparse.ArgumentParser(prog="project-forge-deploy app")
|
|
58
90
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
@@ -64,29 +96,26 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
64
96
|
inventory.add_argument("name")
|
|
65
97
|
inventory.add_argument("--json", action="store_true")
|
|
66
98
|
|
|
99
|
+
isolation = sub.add_parser(
|
|
100
|
+
"isolation",
|
|
101
|
+
help="Read current managed ownership/runtime/route/persistence isolation for an application footprint",
|
|
102
|
+
)
|
|
103
|
+
_add_isolation_footprint(isolation)
|
|
104
|
+
isolation.add_argument(
|
|
105
|
+
"--require-clear",
|
|
106
|
+
action="store_true",
|
|
107
|
+
help="Exit nonzero when the read-only isolation result is blocked",
|
|
108
|
+
)
|
|
109
|
+
isolation.add_argument("--json", action="store_true")
|
|
110
|
+
|
|
67
111
|
deploy = sub.add_parser(
|
|
68
112
|
"deploy",
|
|
69
113
|
help="Deploy one immutable application runtime without modifying routes",
|
|
70
114
|
)
|
|
71
|
-
deploy
|
|
72
|
-
deploy.add_argument("--owner-repo", required=True)
|
|
73
|
-
deploy.add_argument("--environment", required=True)
|
|
74
|
-
deploy.add_argument(
|
|
75
|
-
"--production",
|
|
76
|
-
action="store_true",
|
|
77
|
-
help="Classify this named environment as Production even when its name is not literally 'production'",
|
|
78
|
-
)
|
|
79
|
-
deploy.add_argument("--app-slug", required=True)
|
|
80
|
-
deploy.add_argument("--container-name", required=True)
|
|
115
|
+
_add_isolation_footprint(deploy)
|
|
81
116
|
deploy.add_argument("--image", required=True)
|
|
82
|
-
deploy.add_argument("--runtime-port", type=int, required=True)
|
|
83
117
|
deploy.add_argument("--health-path", required=True)
|
|
84
118
|
deploy.add_argument("--run-as", required=True)
|
|
85
|
-
deploy.add_argument(
|
|
86
|
-
"--persistence-mode",
|
|
87
|
-
choices=("none", "directory"),
|
|
88
|
-
required=True,
|
|
89
|
-
)
|
|
90
119
|
deploy.add_argument("--data-container-path")
|
|
91
120
|
deploy.add_argument(
|
|
92
121
|
"--env",
|
|
@@ -115,6 +144,23 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
115
144
|
_print(app_inventory(args.name), as_json=args.json)
|
|
116
145
|
return 0
|
|
117
146
|
|
|
147
|
+
production_classified = args.production or args.environment == "production"
|
|
148
|
+
if args.command == "isolation":
|
|
149
|
+
result = app_isolation_check(
|
|
150
|
+
args.name,
|
|
151
|
+
owner_repo=args.owner_repo,
|
|
152
|
+
environment=args.environment,
|
|
153
|
+
production=production_classified,
|
|
154
|
+
app_slug=args.app_slug,
|
|
155
|
+
container_name=args.container_name,
|
|
156
|
+
runtime_port=args.runtime_port,
|
|
157
|
+
persistence_mode=args.persistence_mode,
|
|
158
|
+
database_file=args.database_file,
|
|
159
|
+
route_hostnames=args.route_hostname,
|
|
160
|
+
)
|
|
161
|
+
_print(result, as_json=args.json)
|
|
162
|
+
return 2 if args.require_clear and result["state"] != "clear" else 0
|
|
163
|
+
|
|
118
164
|
spec = normalize_app_spec(
|
|
119
165
|
owner_repo=args.owner_repo,
|
|
120
166
|
environment=args.environment,
|
|
@@ -129,10 +175,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
129
175
|
environment_variables=_parse_env(args.env),
|
|
130
176
|
)
|
|
131
177
|
assert_app_spec_matches_persistence(args.name, spec)
|
|
132
|
-
plan = plan_app_deploy(
|
|
178
|
+
plan = plan_app_deploy(
|
|
179
|
+
args.name,
|
|
180
|
+
spec,
|
|
181
|
+
production=production_classified,
|
|
182
|
+
database_file=args.database_file,
|
|
183
|
+
route_hostnames=args.route_hostname,
|
|
184
|
+
)
|
|
133
185
|
plan_view = {key: value for key, value in plan.items() if key != "spec"}
|
|
134
186
|
plan_view["imageSource"] = args.image_source
|
|
135
|
-
production_classified = args.production or plan["environment"] == "production"
|
|
136
187
|
plan_view["productionClassified"] = production_classified
|
|
137
188
|
if args.image_source == "workstation":
|
|
138
189
|
plan_view["targetRegistryCredentialRequired"] = False
|