@stackonward/cli 1.7.0 → 1.8.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/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/resources/components/nuxt/site-source/app/composables/useWebPush.ts +4 -0
- package/dist/resources/components/nuxt/site-source/app/plugins/web-push.ts +52 -0
- package/dist/resources/components/nuxt/site-source/app/web-push/worker.ts +8 -0
- package/dist/resources/components/registry.json +11 -1
- package/dist/resources/registry.json +15 -3
- package/dist/resources/templates/base/{.claude → .codex}/docs/architecture-template.md +1 -1
- package/dist/resources/templates/base/{.claude → .codex}/docs/architecture.md +1 -1
- package/dist/resources/templates/base/{.claude → .codex}/docs/index.md +3 -3
- package/dist/resources/templates/base/{.claude → .codex}/docs/verification.md +1 -1
- package/dist/resources/templates/base/AGENTS.md +24 -24
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/api-design.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/architecture-template.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/check-list.md +3 -3
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/database.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/error-handling.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/index.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/logging.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/mediagen-provider-onboarding-sop.md +2 -2
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/mediagen-provider-quick-reference.md +1 -1
- package/dist/resources/templates/go-backend/{.claude → .codex}/docs/module-standards.md +1 -1
- package/dist/resources/templates/go-backend/.dockerignore +1 -2
- package/dist/resources/templates/go-backend/AGENTS.md +19 -19
- package/dist/resources/templates/go-backend/README.md +5 -1
- package/dist/resources/templates/go-backend/deployments/onex/product-onboarding.example.json +201 -0
- package/dist/resources/templates/go-backend/docs/onex-notifications.md +85 -0
- package/dist/resources/templates/go-backend/docs/openapi-provenance.json +1 -1
- package/dist/resources/templates/go-backend/docs/runtime-provenance.json +23 -2
- package/dist/resources/templates/go-backend/docs/source-provenance.json +124 -6
- package/dist/resources/templates/go-backend/docs/standards-provenance.json +30 -30
- package/dist/resources/templates/go-backend/internal/common/middleware/cors.go +1 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/middleware_test.go +1 -0
- package/dist/resources/templates/go-backend/internal/core/httpclient/safe_post.go +28 -0
- package/dist/resources/templates/go-backend/internal/core/httpclient/safe_post_test.go +56 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/client.go +453 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/client_test.go +772 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/codec.go +33 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/error.go +146 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/error_notification_test.go +29 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/notification/client.go +132 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/notification/client_test.go +222 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/notification/contracts.go +219 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/resilience.go +23 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/v1/transport_policy.go +96 -0
- package/dist/resources/templates/go-backend/internal/products/README.md +1 -1
- package/dist/resources/templates/go-backend/internal/sharedevents/README.md +1 -1
- package/dist/resources/templates/go-backend/scripts/check-openapi-clean-deletion.sh +3 -3
- package/dist/resources/templates/mcp-server/.prettierignore +1 -0
- package/dist/resources/templates/nuxt/{.claude → .codex}/docs/stack.md +10 -0
- package/dist/resources/templates/nuxt/.dockerignore +1 -1
- package/dist/resources/templates/nuxt/.env.example +6 -0
- package/dist/resources/templates/nuxt/.prettierignore +2 -1
- package/dist/resources/templates/nuxt/DESIGN.md +1 -1
- package/dist/resources/templates/nuxt/README.md +8 -0
- package/dist/resources/templates/nuxt/nuxt.config.ts +13 -1
- package/dist/resources/templates/nuxt/package.json +4 -2
- package/package.json +1 -1
- package/dist/resources/templates/base/CLAUDE.md +0 -437
- package/dist/resources/templates/go-backend/CLAUDE.md +0 -1139
- /package/dist/resources/templates/base/{.claude → .codex}/docs/security-lifecycle.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/e2e-standards.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/event-runtime-boundary.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/identifier-contract.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/openapi-contract.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/payment-gateway-onboarding.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/platform-boundary.md +0 -0
- /package/dist/resources/templates/go-backend/{.claude → .codex}/docs/quality-gates.md +0 -0
- /package/dist/resources/templates/mcp-server/{.claude → .codex}/docs/stack.md +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source_repository": "https://onedev.yhy.gd.cn/platform/onex",
|
|
3
3
|
"source_commit": "4fd93f675a6579773d16ab8272395cab8c761670",
|
|
4
|
-
"hash_scope": "Source SHA identifies the inspected working-tree file. Target SHA identifies the distributed template before variable materialization.",
|
|
4
|
+
"hash_scope": "Source SHA identifies the inspected working-tree file. Target SHA identifies the distributed template before variable materialization. Target paths and references use the project-owned AGENTS.md and .codex/docs layout; original upstream source paths and source hashes remain unchanged.",
|
|
5
5
|
"documents": [
|
|
6
6
|
{
|
|
7
7
|
"source": "backend/CLAUDE.md",
|
|
8
|
-
"target": "
|
|
8
|
+
"target": "AGENTS.md",
|
|
9
9
|
"source_sha256": "d263504fd2f396d2aa74034e8d40a0ec992a5351ae75bdcbada39c5b20698136",
|
|
10
|
-
"target_template_sha256": "
|
|
10
|
+
"target_template_sha256": "b342242164bd03ad28cbd775f5786e4e597ca0531aabd74e713c0377fd2fa1b9",
|
|
11
11
|
"source_lines": 1103,
|
|
12
12
|
"target_lines": 1139,
|
|
13
13
|
"source_heading_count": 89,
|
|
@@ -215,9 +215,9 @@
|
|
|
215
215
|
},
|
|
216
216
|
{
|
|
217
217
|
"source": "backend/.claude/docs/api-design.md",
|
|
218
|
-
"target": ".
|
|
218
|
+
"target": ".codex/docs/api-design.md",
|
|
219
219
|
"source_sha256": "9ce2e7b828723587f3673ebe637b5b868853e952934df2ec6a7ee77febe0afb3",
|
|
220
|
-
"target_template_sha256": "
|
|
220
|
+
"target_template_sha256": "bc9cee68ac932c8156421a7aee4ae5056365fa92a2efdc67b187eead48cede86",
|
|
221
221
|
"source_lines": 432,
|
|
222
222
|
"target_lines": 486,
|
|
223
223
|
"source_heading_count": 9,
|
|
@@ -557,9 +557,9 @@
|
|
|
557
557
|
},
|
|
558
558
|
{
|
|
559
559
|
"source": ".claude/docs/architecture-template.md",
|
|
560
|
-
"target": ".
|
|
560
|
+
"target": ".codex/docs/architecture-template.md",
|
|
561
561
|
"source_sha256": "b74c529abec5ff160bd61942f98f172bbe70170490eaa6aba32d32ce70ec4c45",
|
|
562
|
-
"target_template_sha256": "
|
|
562
|
+
"target_template_sha256": "ac8caafbd4dd1f4b75818368583dd90c24dfa0586f0858d70d91a16fd6a425b8",
|
|
563
563
|
"source_lines": 449,
|
|
564
564
|
"target_lines": 449,
|
|
565
565
|
"source_heading_count": 63,
|
|
@@ -580,9 +580,9 @@
|
|
|
580
580
|
},
|
|
581
581
|
{
|
|
582
582
|
"source": "backend/.claude/docs/check-list.md",
|
|
583
|
-
"target": ".
|
|
583
|
+
"target": ".codex/docs/check-list.md",
|
|
584
584
|
"source_sha256": "abe272bec01bca44fca1e67050f7dd2d25c1213ab79c66c501cb4e47b695ec29",
|
|
585
|
-
"target_template_sha256": "
|
|
585
|
+
"target_template_sha256": "c3975fc04e638464b40de48819ffa535b174f69a43082e84ebb98c4a7c8d9e76",
|
|
586
586
|
"source_lines": 155,
|
|
587
587
|
"target_lines": 155,
|
|
588
588
|
"source_heading_count": 19,
|
|
@@ -614,9 +614,9 @@
|
|
|
614
614
|
},
|
|
615
615
|
{
|
|
616
616
|
"source": "backend/.claude/docs/database.md",
|
|
617
|
-
"target": ".
|
|
617
|
+
"target": ".codex/docs/database.md",
|
|
618
618
|
"source_sha256": "ce1327c9f0868566b3960795e22c46774b9ffdd39505492a1277c9f7343eff67",
|
|
619
|
-
"target_template_sha256": "
|
|
619
|
+
"target_template_sha256": "bbdd7c697beef2bd550846f54c27c11d7bd66ef9daee00a0674d6042b7be4993",
|
|
620
620
|
"source_lines": 369,
|
|
621
621
|
"target_lines": 369,
|
|
622
622
|
"source_heading_count": 14,
|
|
@@ -681,7 +681,7 @@
|
|
|
681
681
|
},
|
|
682
682
|
{
|
|
683
683
|
"source": "backend/.claude/docs/e2e-standards.md",
|
|
684
|
-
"target": ".
|
|
684
|
+
"target": ".codex/docs/e2e-standards.md",
|
|
685
685
|
"source_sha256": "719aecf2f91587956b175708ed43a98e5ea4ed965ca0fde8bb74855eecd7f260",
|
|
686
686
|
"target_template_sha256": "719aecf2f91587956b175708ed43a98e5ea4ed965ca0fde8bb74855eecd7f260",
|
|
687
687
|
"source_lines": 161,
|
|
@@ -692,9 +692,9 @@
|
|
|
692
692
|
},
|
|
693
693
|
{
|
|
694
694
|
"source": "backend/.claude/docs/error-handling.md",
|
|
695
|
-
"target": ".
|
|
695
|
+
"target": ".codex/docs/error-handling.md",
|
|
696
696
|
"source_sha256": "a7f3200a4385bdf5952b77915e645edf0f5b5b2278f43c5658326e0f016d9c4e",
|
|
697
|
-
"target_template_sha256": "
|
|
697
|
+
"target_template_sha256": "fb20722499d1e7c329cfa22b937c4cd8fbebc55c1de59549ba615edeb2c397eb",
|
|
698
698
|
"source_lines": 258,
|
|
699
699
|
"target_lines": 558,
|
|
700
700
|
"source_heading_count": 7,
|
|
@@ -1155,7 +1155,7 @@
|
|
|
1155
1155
|
},
|
|
1156
1156
|
{
|
|
1157
1157
|
"source": "backend/.claude/docs/event-runtime-boundary.md",
|
|
1158
|
-
"target": ".
|
|
1158
|
+
"target": ".codex/docs/event-runtime-boundary.md",
|
|
1159
1159
|
"source_sha256": "18130708d01b173bc2e7526f2ab530ba886910234db4260e9dd375d141efaeeb",
|
|
1160
1160
|
"target_template_sha256": "18130708d01b173bc2e7526f2ab530ba886910234db4260e9dd375d141efaeeb",
|
|
1161
1161
|
"source_lines": 124,
|
|
@@ -1166,7 +1166,7 @@
|
|
|
1166
1166
|
},
|
|
1167
1167
|
{
|
|
1168
1168
|
"source": "backend/.claude/docs/identifier-contract.md",
|
|
1169
|
-
"target": ".
|
|
1169
|
+
"target": ".codex/docs/identifier-contract.md",
|
|
1170
1170
|
"source_sha256": "27cb70840f24e42b9d4b85e713b67635ce6e101c716687ab613379d1343ea890",
|
|
1171
1171
|
"target_template_sha256": "27cb70840f24e42b9d4b85e713b67635ce6e101c716687ab613379d1343ea890",
|
|
1172
1172
|
"source_lines": 195,
|
|
@@ -1177,9 +1177,9 @@
|
|
|
1177
1177
|
},
|
|
1178
1178
|
{
|
|
1179
1179
|
"source": "backend/.claude/docs/index.md",
|
|
1180
|
-
"target": ".
|
|
1180
|
+
"target": ".codex/docs/index.md",
|
|
1181
1181
|
"source_sha256": "bb43af098ff5b871488df6e60c34a15ef476786fef406a4ee27103de23c3b62f",
|
|
1182
|
-
"target_template_sha256": "
|
|
1182
|
+
"target_template_sha256": "6879062dd16f506f6014f0f8f3b6962e1a9765bb52f562ade0d67cb49736545c",
|
|
1183
1183
|
"source_lines": 17,
|
|
1184
1184
|
"target_lines": 22,
|
|
1185
1185
|
"source_heading_count": 1,
|
|
@@ -1211,9 +1211,9 @@
|
|
|
1211
1211
|
},
|
|
1212
1212
|
{
|
|
1213
1213
|
"source": "backend/.claude/docs/logging.md",
|
|
1214
|
-
"target": ".
|
|
1214
|
+
"target": ".codex/docs/logging.md",
|
|
1215
1215
|
"source_sha256": "7f2cf9e546c249e848b461b941565aa66d39627420b2df761009d4426e6267d3",
|
|
1216
|
-
"target_template_sha256": "
|
|
1216
|
+
"target_template_sha256": "0a69dd766fc803a8cb5dbb39ffcdd2af1f7612a769b08ddd06babe76673aa71f",
|
|
1217
1217
|
"source_lines": 276,
|
|
1218
1218
|
"target_lines": 314,
|
|
1219
1219
|
"source_heading_count": 12,
|
|
@@ -1355,9 +1355,9 @@
|
|
|
1355
1355
|
},
|
|
1356
1356
|
{
|
|
1357
1357
|
"source": "backend/.claude/docs/mediagen-provider-onboarding-sop.md",
|
|
1358
|
-
"target": ".
|
|
1358
|
+
"target": ".codex/docs/mediagen-provider-onboarding-sop.md",
|
|
1359
1359
|
"source_sha256": "e063b530b72d0cb42de3dd76d07b020e28f1b4b3bfcc72e2105099c7366ca6c4",
|
|
1360
|
-
"target_template_sha256": "
|
|
1360
|
+
"target_template_sha256": "16ce86e7681fbd12c217299faa42969241282fb9e5eb3bfe1105b97a9facea43",
|
|
1361
1361
|
"source_lines": 915,
|
|
1362
1362
|
"target_lines": 917,
|
|
1363
1363
|
"source_heading_count": 60,
|
|
@@ -1378,9 +1378,9 @@
|
|
|
1378
1378
|
},
|
|
1379
1379
|
{
|
|
1380
1380
|
"source": "backend/.claude/docs/mediagen-provider-quick-reference.md",
|
|
1381
|
-
"target": ".
|
|
1381
|
+
"target": ".codex/docs/mediagen-provider-quick-reference.md",
|
|
1382
1382
|
"source_sha256": "3c661d4fa59468601d5041ec9990cfe4dade3c8fddac50431b85c8417c45376a",
|
|
1383
|
-
"target_template_sha256": "
|
|
1383
|
+
"target_template_sha256": "9a9f18c167cb511e4beb44cd124211a47826a46fb3335baf1fab15341b0265d0",
|
|
1384
1384
|
"source_lines": 193,
|
|
1385
1385
|
"target_lines": 195,
|
|
1386
1386
|
"source_heading_count": 13,
|
|
@@ -1401,9 +1401,9 @@
|
|
|
1401
1401
|
},
|
|
1402
1402
|
{
|
|
1403
1403
|
"source": "backend/.claude/docs/module-standards.md",
|
|
1404
|
-
"target": ".
|
|
1404
|
+
"target": ".codex/docs/module-standards.md",
|
|
1405
1405
|
"source_sha256": "7a9b6651f493b34fcea0d136f4c43b5d0d9fd840bfafbd5d3955246baac649b6",
|
|
1406
|
-
"target_template_sha256": "
|
|
1406
|
+
"target_template_sha256": "a0573ece7b5b8555e501d043405e97f56ceca4b2cfa393b7e60f816f609c5f06",
|
|
1407
1407
|
"source_lines": 307,
|
|
1408
1408
|
"target_lines": 309,
|
|
1409
1409
|
"source_heading_count": 13,
|
|
@@ -1479,7 +1479,7 @@
|
|
|
1479
1479
|
},
|
|
1480
1480
|
{
|
|
1481
1481
|
"source": "backend/.claude/docs/openapi-contract.md",
|
|
1482
|
-
"target": ".
|
|
1482
|
+
"target": ".codex/docs/openapi-contract.md",
|
|
1483
1483
|
"source_sha256": "047b32cb13001115d9431566f94839a8bf00c689624c59de3a7a5aa484ba9d90",
|
|
1484
1484
|
"target_template_sha256": "047b32cb13001115d9431566f94839a8bf00c689624c59de3a7a5aa484ba9d90",
|
|
1485
1485
|
"source_lines": 141,
|
|
@@ -1490,7 +1490,7 @@
|
|
|
1490
1490
|
},
|
|
1491
1491
|
{
|
|
1492
1492
|
"source": "backend/.claude/docs/payment-gateway-onboarding.md",
|
|
1493
|
-
"target": ".
|
|
1493
|
+
"target": ".codex/docs/payment-gateway-onboarding.md",
|
|
1494
1494
|
"source_sha256": "ed9457cb90e310c0316864a7926629928fc3462aaf36a42c418f6ea20a27a509",
|
|
1495
1495
|
"target_template_sha256": "6bd8cf4fd81c276840ba5c41441919262c79b1446883bf3539350cbf0018a94b",
|
|
1496
1496
|
"source_lines": 281,
|
|
@@ -1513,7 +1513,7 @@
|
|
|
1513
1513
|
},
|
|
1514
1514
|
{
|
|
1515
1515
|
"source": "backend/.claude/docs/platform-boundary.md",
|
|
1516
|
-
"target": ".
|
|
1516
|
+
"target": ".codex/docs/platform-boundary.md",
|
|
1517
1517
|
"source_sha256": "73fe23acc1ba5b5e9e257345051e9880e7ebe7cd934f04457e7d8c31f2e0e5bd",
|
|
1518
1518
|
"target_template_sha256": "73fe23acc1ba5b5e9e257345051e9880e7ebe7cd934f04457e7d8c31f2e0e5bd",
|
|
1519
1519
|
"source_lines": 191,
|
|
@@ -1524,7 +1524,7 @@
|
|
|
1524
1524
|
},
|
|
1525
1525
|
{
|
|
1526
1526
|
"source": ".claude/docs/quality-gates.md",
|
|
1527
|
-
"target": ".
|
|
1527
|
+
"target": ".codex/docs/quality-gates.md",
|
|
1528
1528
|
"source_sha256": "b01d02a15f30bf1bdefc05d4070966bf30b4259a6b2f8d2031d119ef9a706cd3",
|
|
1529
1529
|
"target_template_sha256": "b10ceb82a6880b258f3a105a9f93091910e999a7c55ac3c310e0fc423bbb2ae3",
|
|
1530
1530
|
"source_lines": 110,
|
|
@@ -589,6 +589,7 @@ func TestCORS_ExposeCheckoutClientHeaders(t *testing.T) {
|
|
|
589
589
|
assert.True(t, strings.Contains(allowHeaders, types.HeaderDeviceID))
|
|
590
590
|
assert.True(t, strings.Contains(allowHeaders, "Checkout-Client-Nonce"))
|
|
591
591
|
assert.True(t, strings.Contains(allowHeaders, "Checkout-Presentation-Accept"))
|
|
592
|
+
assert.True(t, strings.Contains(allowHeaders, "If-Match"))
|
|
592
593
|
assert.True(t, strings.Contains(allowHeaders, types.HeaderIdempotencyKey))
|
|
593
594
|
for _, header := range strings.Split(allowHeaders, ", ") {
|
|
594
595
|
assert.NotEqual(t, "Idempotency-Key", header)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package httpclient
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"net/http"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// NewSafePostClient 复用下载 owner 的公网解析与连接钉住规则,但禁止重定向和自动重试。
|
|
9
|
+
func NewSafePostClient(options SafeDownloadClientOptions) *http.Client {
|
|
10
|
+
transport := &safePostTransport{download: &safeDownloadTransport{options: options}}
|
|
11
|
+
return &http.Client{Timeout: transport.download.timeout(), Transport: transport, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type safePostTransport struct{ download *safeDownloadTransport }
|
|
15
|
+
|
|
16
|
+
func (t *safePostTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
17
|
+
if req == nil || req.URL == nil || req.Method != http.MethodPost || req.URL.Scheme != "https" {
|
|
18
|
+
return nil, fmt.Errorf("safe outbound request requires HTTPS POST")
|
|
19
|
+
}
|
|
20
|
+
pinned, err := t.download.validateAndPin(req.Context(), req.URL.String())
|
|
21
|
+
if err != nil {
|
|
22
|
+
return nil, err
|
|
23
|
+
}
|
|
24
|
+
request := req.Clone(req.Context())
|
|
25
|
+
request.URL = cloneURL(pinned.URL)
|
|
26
|
+
request.Host = ""
|
|
27
|
+
return t.download.doPinnedRequest(request, pinned)
|
|
28
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package httpclient
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"io"
|
|
6
|
+
"net"
|
|
7
|
+
"net/http"
|
|
8
|
+
"strings"
|
|
9
|
+
"testing"
|
|
10
|
+
|
|
11
|
+
"github.com/stretchr/testify/require"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
func TestSafePostPinsValidatedAddressAndNeverFollowsRedirect(t *testing.T) {
|
|
15
|
+
calls := 0
|
|
16
|
+
client := NewSafePostClient(SafeDownloadClientOptions{LookupIP: func(context.Context, string) ([]net.IP, error) { return []net.IP{net.ParseIP("93.184.216.34")}, nil }, sendPinnedRequest: func(req *http.Request, pinned pinnedDownloadURL) (*http.Response, error) {
|
|
17
|
+
calls++
|
|
18
|
+
require.Equal(t, "93.184.216.34", pinned.IP.String())
|
|
19
|
+
require.Equal(t, "push.example.com", req.URL.Host)
|
|
20
|
+
body, err := io.ReadAll(req.Body)
|
|
21
|
+
require.NoError(t, err)
|
|
22
|
+
require.Equal(t, "ciphertext", string(body))
|
|
23
|
+
return &http.Response{StatusCode: 307, Header: http.Header{"Location": []string{"https://127.0.0.1/private"}}, Body: io.NopCloser(strings.NewReader("")), Request: req}, nil
|
|
24
|
+
}})
|
|
25
|
+
req, err := http.NewRequest(http.MethodPost, "https://push.example.com/path", strings.NewReader("ciphertext"))
|
|
26
|
+
require.NoError(t, err)
|
|
27
|
+
resp, err := client.Do(req)
|
|
28
|
+
require.NoError(t, err)
|
|
29
|
+
defer resp.Body.Close()
|
|
30
|
+
require.Equal(t, 307, resp.StatusCode)
|
|
31
|
+
require.Equal(t, 1, calls)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func TestSafePostRejectsPrivateAndMixedDNSBeforeNetwork(t *testing.T) {
|
|
35
|
+
for _, ips := range [][]net.IP{{net.ParseIP("127.0.0.1")}, {net.ParseIP("93.184.216.34"), net.ParseIP("10.0.0.1")}, {net.ParseIP("::ffff:127.0.0.1")}} {
|
|
36
|
+
client := NewSafePostClient(SafeDownloadClientOptions{LookupIP: func(context.Context, string) ([]net.IP, error) { return ips, nil }, sendPinnedRequest: func(*http.Request, pinnedDownloadURL) (*http.Response, error) {
|
|
37
|
+
t.Fatal("unsafe address reached network")
|
|
38
|
+
return nil, nil
|
|
39
|
+
}})
|
|
40
|
+
req, err := http.NewRequest(http.MethodPost, "https://push.example.com/path", strings.NewReader("ciphertext"))
|
|
41
|
+
require.NoError(t, err)
|
|
42
|
+
_, err = client.Do(req)
|
|
43
|
+
require.True(t, IsSafeDownloadValidationError(err))
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func TestSafePostRejectsUnencryptedRequestsBeforeDNS(t *testing.T) {
|
|
48
|
+
client := NewSafePostClient(SafeDownloadClientOptions{LookupIP: func(context.Context, string) ([]net.IP, error) {
|
|
49
|
+
t.Fatal("unencrypted request reached DNS")
|
|
50
|
+
return nil, nil
|
|
51
|
+
}})
|
|
52
|
+
req, err := http.NewRequest(http.MethodPost, "http://push.example.com/path", strings.NewReader("ciphertext"))
|
|
53
|
+
require.NoError(t, err)
|
|
54
|
+
_, err = client.Do(req)
|
|
55
|
+
require.ErrorContains(t, err, "requires HTTPS POST")
|
|
56
|
+
}
|