@stackonward/cli 0.0.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +4588 -205
- package/dist/index.js.map +1 -1
- package/dist/resources/apple/.claude/docs/architecture-template.md +54 -0
- package/dist/resources/apple/.claude/docs/architecture.md +52 -0
- package/dist/resources/apple/.claude/docs/index.md +13 -0
- package/dist/resources/apple/.claude/docs/security-lifecycle.md +57 -0
- package/dist/resources/apple/.claude/docs/stack.md +93 -0
- package/dist/resources/apple/.claude/docs/verification.md +63 -0
- package/dist/resources/apple/AGENTS.md +397 -0
- package/dist/resources/apple/CLAUDE.md +397 -0
- package/dist/resources/apple/Gemfile +2 -0
- package/dist/resources/apple/Gemfile.lock +365 -0
- package/dist/resources/apple/_gitignore +14 -0
- package/dist/resources/apple/fastlane/Fastfile +123 -0
- package/dist/resources/components/nuxt/site-source/app/app.vue +42 -0
- package/dist/resources/components/nuxt/site-source/app/assets/css/site-shell.css +1035 -0
- package/dist/resources/components/nuxt/site-source/app/assets/icons/brand/.gitkeep +0 -0
- package/dist/resources/components/nuxt/site-source/app/assets/icons/common/.gitkeep +0 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/ApplicationHeader.vue +35 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/ApplicationShell.vue +56 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/ApplicationSidebar.vue +40 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/BackToTop.vue +42 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/ContentArticlePage.vue +40 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/ContentListPage.vue +30 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/CookieConsent.vue +18 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/MarketingFooter.vue +52 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/MarketingHeader.vue +106 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/MarketingShell.vue +35 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/SiteBrand.vue +10 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/StaticPage.vue +21 -0
- package/dist/resources/components/nuxt/site-source/app/components/site/ToastViewport.vue +25 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/BaseButton.vue +86 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/BaseGradientBorder.vue +59 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/BaseModal.vue +131 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/BasePopover.vue +150 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/BaseText.vue +138 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/CheckoutStatus.vue +112 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/CheckoutSummary.vue +172 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/GoogleSignInButton.vue +113 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/InfiniteScroll.vue +123 -0
- package/dist/resources/components/nuxt/site-source/app/components/ui/YoutubeEmbed.vue +126 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useAnalytics.ts +24 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useCheckout.ts +121 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useConsent.ts +31 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useGoogleIdentity.ts +163 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useNavigation.ts +11 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useSeo.ts +33 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useSiteShell.ts +58 -0
- package/dist/resources/components/nuxt/site-source/app/composables/useToasts.ts +48 -0
- package/dist/resources/components/nuxt/site-source/app/layouts/app.vue +5 -0
- package/dist/resources/components/nuxt/site-source/app/layouts/default.vue +5 -0
- package/dist/resources/components/nuxt/site-source/app/plugins/analytics.client.ts +121 -0
- package/dist/resources/components/nuxt/site-source/app/plugins/google-identity.client.ts +24 -0
- package/dist/resources/components/nuxt/site-source/app/theme/accordion.ts +9 -0
- package/dist/resources/components/nuxt/site-source/app/theme/breadcrumb.ts +8 -0
- package/dist/resources/components/nuxt/site-source/app/theme/button.ts +92 -0
- package/dist/resources/components/nuxt/site-source/app/theme/carousel.ts +11 -0
- package/dist/resources/components/nuxt/site-source/app/theme/checkbox.ts +12 -0
- package/dist/resources/components/nuxt/site-source/app/theme/index.ts +30 -0
- package/dist/resources/components/nuxt/site-source/app/theme/input.ts +47 -0
- package/dist/resources/components/nuxt/site-source/app/theme/modal.ts +9 -0
- package/dist/resources/components/nuxt/site-source/app/theme/pagination.ts +6 -0
- package/dist/resources/components/nuxt/site-source/app/theme/select.ts +23 -0
- package/dist/resources/components/nuxt/site-source/app/theme/stepper.ts +10 -0
- package/dist/resources/components/nuxt/site-source/app/theme/toast.ts +8 -0
- package/dist/resources/components/nuxt/site-source/app/theme/tooltip.ts +6 -0
- package/dist/resources/components/nuxt/site-source/app/types/site-shell.ts +85 -0
- package/dist/resources/components/react/ui/Button.tsx +73 -0
- package/dist/resources/components/react/ui/Input.tsx +44 -0
- package/dist/resources/components/registry.json +355 -0
- package/dist/resources/components/vue/feedback/Toast.vue +120 -0
- package/dist/resources/components/vue/feedback/useToast.ts +70 -0
- package/dist/resources/components/vue/media/FileUpload.vue +229 -0
- package/dist/resources/components/vue/media/VideoPlayer.vue +157 -0
- package/dist/resources/components/vue/ui/AppImage.vue +147 -0
- package/dist/resources/components/vue/ui/BottomSheet.vue +217 -0
- package/dist/resources/components/vue/ui/Button.vue +154 -0
- package/dist/resources/components/vue/ui/Card.vue +111 -0
- package/dist/resources/components/vue/ui/Input.vue +113 -0
- package/dist/resources/components/vue/ui/Modal.vue +193 -0
- package/dist/resources/components/vue/ui/ScrollArea.vue +163 -0
- package/dist/resources/components/vue/ui/Tooltip.vue +115 -0
- package/dist/resources/registry.json +158 -0
- package/dist/resources/snippets/node/cache.ts +116 -0
- package/dist/resources/snippets/node/date.ts +126 -0
- package/dist/resources/snippets/node/logger.ts +104 -0
- package/dist/resources/snippets/node/validation.ts +132 -0
- package/dist/resources/snippets/react/useDebounce.ts +90 -0
- package/dist/resources/snippets/registry.json +65 -0
- package/dist/resources/snippets/vue/useAsync.ts +96 -0
- package/dist/resources/snippets/vue/usePagination.ts +102 -0
- package/dist/resources/templates/base/.claude/docs/architecture-template.md +459 -0
- package/dist/resources/templates/base/.claude/docs/architecture.md +137 -0
- package/dist/resources/templates/base/.claude/docs/index.md +42 -0
- package/dist/resources/templates/base/.claude/docs/security-lifecycle.md +129 -0
- package/dist/resources/templates/base/.claude/docs/verification.md +121 -0
- package/dist/resources/templates/base/AGENTS.md +415 -0
- package/dist/resources/templates/base/CLAUDE.md +415 -0
- package/dist/resources/templates/go-backend/.claude/docs/api-design.md +486 -0
- package/dist/resources/templates/go-backend/.claude/docs/architecture-template.md +449 -0
- package/dist/resources/templates/go-backend/.claude/docs/check-list.md +155 -0
- package/dist/resources/templates/go-backend/.claude/docs/database.md +369 -0
- package/dist/resources/templates/go-backend/.claude/docs/e2e-standards.md +161 -0
- package/dist/resources/templates/go-backend/.claude/docs/error-handling.md +558 -0
- package/dist/resources/templates/go-backend/.claude/docs/event-runtime-boundary.md +124 -0
- package/dist/resources/templates/go-backend/.claude/docs/identifier-contract.md +195 -0
- package/dist/resources/templates/go-backend/.claude/docs/index.md +22 -0
- package/dist/resources/templates/go-backend/.claude/docs/logging.md +314 -0
- package/dist/resources/templates/go-backend/.claude/docs/mediagen-provider-onboarding-sop.md +917 -0
- package/dist/resources/templates/go-backend/.claude/docs/mediagen-provider-quick-reference.md +195 -0
- package/dist/resources/templates/go-backend/.claude/docs/module-standards.md +309 -0
- package/dist/resources/templates/go-backend/.claude/docs/openapi-contract.md +141 -0
- package/dist/resources/templates/go-backend/.claude/docs/payment-gateway-onboarding.md +283 -0
- package/dist/resources/templates/go-backend/.claude/docs/platform-boundary.md +191 -0
- package/dist/resources/templates/go-backend/.claude/docs/quality-gates.md +112 -0
- package/dist/resources/templates/go-backend/.dockerignore +6 -0
- package/dist/resources/templates/go-backend/.env.example +13 -0
- package/dist/resources/templates/go-backend/.gitattributes +2 -0
- package/dist/resources/templates/go-backend/AGENTS.md +1139 -0
- package/dist/resources/templates/go-backend/CLAUDE.md +1139 -0
- package/dist/resources/templates/go-backend/Dockerfile +14 -0
- package/dist/resources/templates/go-backend/Makefile +71 -0
- package/dist/resources/templates/go-backend/README.md +66 -0
- package/dist/resources/templates/go-backend/_gitignore +10 -0
- package/dist/resources/templates/go-backend/api/openapi/README.md +29 -0
- package/dist/resources/templates/go-backend/api/openapi/dist/artifact-manifest.json +19 -0
- package/dist/resources/templates/go-backend/api/openapi/dist/conformance-matrix.json +276 -0
- package/dist/resources/templates/go-backend/api/openapi/document.go +30 -0
- package/dist/resources/templates/go-backend/api/openapi/package.json +28 -0
- package/dist/resources/templates/go-backend/api/openapi/pnpm-lock.yaml +3052 -0
- package/dist/resources/templates/go-backend/api/openapi/redocly-source.yaml +18 -0
- package/dist/resources/templates/go-backend/api/openapi/redocly.yaml +8 -0
- package/dist/resources/templates/go-backend/api/openapi/sdk-generators.json +16 -0
- package/dist/resources/templates/go-backend/api/openapi/service-registry.json +39 -0
- package/dist/resources/templates/go-backend/api/openapi/services/product-api/conformance/runtime.arazzo.yaml +65 -0
- package/dist/resources/templates/go-backend/api/openapi/services/product-api/dist/internal.openapi.json +327 -0
- package/dist/resources/templates/go-backend/api/openapi/services/product-api/dist/runtime-contract.json +56 -0
- package/dist/resources/templates/go-backend/api/openapi/services/product-api/openapi.yaml +222 -0
- package/dist/resources/templates/go-backend/api/openapi/services/worker/conformance/runtime.arazzo.yaml +65 -0
- package/dist/resources/templates/go-backend/api/openapi/services/worker/dist/internal.openapi.json +327 -0
- package/dist/resources/templates/go-backend/api/openapi/services/worker/dist/runtime-contract.json +56 -0
- package/dist/resources/templates/go-backend/api/openapi/services/worker/openapi.yaml +222 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/breaking.mjs +416 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/build.mjs +103 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/conformance_coverage.mjs +111 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/contract_compiler.mjs +62 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/contract_policy.mjs +208 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/delegated_contract.mjs +302 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/deterministic_archive.mjs +69 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/documentation_example_privacy.mjs +93 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/documentation_projection.mjs +498 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/documentation_quality.mjs +346 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/git_artifact_history.mjs +188 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/manifest.mjs +170 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/overlay.mjs +98 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/project.mjs +549 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/route_contract.mjs +156 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/runtime_conformance.mjs +193 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/scalar_asset_localization.mjs +164 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/sdk_generator.mjs +229 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/semantic_version.mjs +64 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/service_contract_inputs.mjs +16 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/breaking.test.mjs +365 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/build.test.mjs +42 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/conformance_coverage.test.mjs +88 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/contract_policy.test.mjs +257 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/delegated_contract.test.mjs +205 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/documentation_example_privacy.test.mjs +51 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/documentation_projection.test.mjs +368 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/documentation_quality.test.mjs +151 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/git_artifact_history.test.mjs +60 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/head_policy.test.mjs +8 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/overlay.test.mjs +44 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/projection.test.mjs +270 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/redocly_documentation_rules.test.mjs +146 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/release_manifest.test.mjs +76 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/route_contract.test.mjs +119 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/runtime_conformance.test.mjs +75 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/scalar_asset_localization.test.mjs +50 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/sdk_generator.test.mjs +31 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/semantic_version.test.mjs +60 -0
- package/dist/resources/templates/go-backend/api/openapi/tooling/test/service_contract_inputs.test.mjs +27 -0
- package/dist/resources/templates/go-backend/cmd/internal/runtime/resources.go +125 -0
- package/dist/resources/templates/go-backend/cmd/internal/runtime/runtime.go +102 -0
- package/dist/resources/templates/go-backend/cmd/internal/runtime/runtime_test.go +70 -0
- package/dist/resources/templates/go-backend/cmd/product-api/lifecycle_test.go +58 -0
- package/dist/resources/templates/go-backend/cmd/product-api/main.go +32 -0
- package/dist/resources/templates/go-backend/cmd/product-api/wire.go +13 -0
- package/dist/resources/templates/go-backend/cmd/product-api/wire_gen.go +94 -0
- package/dist/resources/templates/go-backend/cmd/worker/main.go +47 -0
- package/dist/resources/templates/go-backend/cmd/worker/wire.go +14 -0
- package/dist/resources/templates/go-backend/cmd/worker/wire_gen.go +111 -0
- package/dist/resources/templates/go-backend/configs/config.yaml +37 -0
- package/dist/resources/templates/go-backend/deployments/compose.yaml +71 -0
- package/dist/resources/templates/go-backend/docs/openapi-provenance.json +489 -0
- package/dist/resources/templates/go-backend/docs/runtime-provenance.json +175 -0
- package/dist/resources/templates/go-backend/docs/source-provenance.json +3568 -0
- package/dist/resources/templates/go-backend/docs/standards-provenance.json +1624 -0
- package/dist/resources/templates/go-backend/go.mod +256 -0
- package/dist/resources/templates/go-backend/go.sum +805 -0
- package/dist/resources/templates/go-backend/internal/common/canonicaljson/canonical.go +370 -0
- package/dist/resources/templates/go-backend/internal/common/canonicaljson/canonical_test.go +223 -0
- package/dist/resources/templates/go-backend/internal/common/checkoutbff/contracts.go +125 -0
- package/dist/resources/templates/go-backend/internal/common/checkoutbff/platform_client.go +212 -0
- package/dist/resources/templates/go-backend/internal/common/checkoutbff/platform_client_test.go +319 -0
- package/dist/resources/templates/go-backend/internal/common/contentaccess/contentaccess.go +50 -0
- package/dist/resources/templates/go-backend/internal/common/contracts/contact.go +85 -0
- package/dist/resources/templates/go-backend/internal/common/ctxutil/identity.go +20 -0
- package/dist/resources/templates/go-backend/internal/common/ctxutil/product.go +53 -0
- package/dist/resources/templates/go-backend/internal/common/enumdomain/payment.go +12 -0
- package/dist/resources/templates/go-backend/internal/common/enums/dto_admin.go +9 -0
- package/dist/resources/templates/go-backend/internal/common/enums/enum.go +1247 -0
- package/dist/resources/templates/go-backend/internal/common/enums/handler_admin.go +66 -0
- package/dist/resources/templates/go-backend/internal/common/enums/module.go +46 -0
- package/dist/resources/templates/go-backend/internal/common/enums/provider.go +10 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register.go +11 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_audit.go +274 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_command_replay.go +12 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_config.go +27 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_locale.go +37 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_ops.go +14 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_outbox.go +15 -0
- package/dist/resources/templates/go-backend/internal/common/enums/register_rule_expression.go +63 -0
- package/dist/resources/templates/go-backend/internal/common/enums/registry.go +77 -0
- package/dist/resources/templates/go-backend/internal/common/httporigin/origin.go +62 -0
- package/dist/resources/templates/go-backend/internal/common/httporigin/origin_test.go +38 -0
- package/dist/resources/templates/go-backend/internal/common/iamcredential/plaintext.go +35 -0
- package/dist/resources/templates/go-backend/internal/common/iamcredential/plaintext_test.go +29 -0
- package/dist/resources/templates/go-backend/internal/common/iamscope/scope.go +212 -0
- package/dist/resources/templates/go-backend/internal/common/iamscope/scope_binding.go +26 -0
- package/dist/resources/templates/go-backend/internal/common/iamscope/scope_filter.go +173 -0
- package/dist/resources/templates/go-backend/internal/common/iamscope/scope_filter_test.go +279 -0
- package/dist/resources/templates/go-backend/internal/common/internalapi/authorization_details.go +10 -0
- package/dist/resources/templates/go-backend/internal/common/internalapi/route_permission_policies.go +660 -0
- package/dist/resources/templates/go-backend/internal/common/internalapi/route_permission_policies_test.go +331 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/audience_token_source.go +166 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/bootstrap_token_exchanger.go +183 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/bound_service_token_signer.go +52 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/delegated_access_token_exchanger.go +189 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/delegated_access_token_exchanger_test.go +159 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/product_scoped_service_token_signer.go +92 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/provider.go +25 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/request_signer.go +86 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/resolver.go +69 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/resolver_test.go +42 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/route_scope.go +95 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/route_scope_test.go +78 -0
- package/dist/resources/templates/go-backend/internal/common/internalservice/service_identity_test.go +387 -0
- package/dist/resources/templates/go-backend/internal/common/jsonschema/compiler.go +100 -0
- package/dist/resources/templates/go-backend/internal/common/jsonschema/compiler_test.go +41 -0
- package/dist/resources/templates/go-backend/internal/common/jwksapi/handler.go +83 -0
- package/dist/resources/templates/go-backend/internal/common/jwksapi/handler_test.go +104 -0
- package/dist/resources/templates/go-backend/internal/common/locale/locale.go +145 -0
- package/dist/resources/templates/go-backend/internal/common/locale/locale_test.go +75 -0
- package/dist/resources/templates/go-backend/internal/common/mediaref/mediaref.go +54 -0
- package/dist/resources/templates/go-backend/internal/common/mediaref/mediaref_test.go +77 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/apikey_auth.go +320 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/apikey_throttle.go +158 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/auth.go +40 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/auth_test.go +50 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/client_context.go +86 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/cors.go +68 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/event_context.go +18 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/gateway_identity.go +279 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/helpers.go +159 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/iam_delegated_route_permission.go +171 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/iam_delegated_token_auth.go +151 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/iam_delegated_token_auth_test.go +99 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/iam_service_identity.go +138 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/iam_service_token_auth.go +74 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/idempotent.go +273 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/idempotent_test.go +83 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/internal_route_permission.go +45 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/internal_route_permission_test.go +186 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/logging.go +191 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/metrics.go +45 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/middleware_test.go +1516 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/principal_context.go +160 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/principal_context_test.go +355 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/product_context.go +100 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/recovery.go +40 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/referral_attribution.go +178 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/requestid.go +48 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/resource_permission.go +790 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/resource_permission_test.go +440 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/service_credential_auth.go +67 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/tenant.go +148 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/throttle.go +310 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/trusted_client_ip.go +23 -0
- package/dist/resources/templates/go-backend/internal/common/middleware/trusted_client_ip_test.go +60 -0
- package/dist/resources/templates/go-backend/internal/common/money/currency.go +25 -0
- package/dist/resources/templates/go-backend/internal/common/money/errors.go +23 -0
- package/dist/resources/templates/go-backend/internal/common/money/format.go +123 -0
- package/dist/resources/templates/go-backend/internal/common/money/format_test.go +204 -0
- package/dist/resources/templates/go-backend/internal/common/money/gateway.go +144 -0
- package/dist/resources/templates/go-backend/internal/common/money/gateway_test.go +165 -0
- package/dist/resources/templates/go-backend/internal/common/money/rounding.go +56 -0
- package/dist/resources/templates/go-backend/internal/common/money/rounding_test.go +51 -0
- package/dist/resources/templates/go-backend/internal/common/principal/context.go +56 -0
- package/dist/resources/templates/go-backend/internal/common/principal/principal.go +49 -0
- package/dist/resources/templates/go-backend/internal/common/productcode/code.go +24 -0
- package/dist/resources/templates/go-backend/internal/common/productcode/code_test.go +35 -0
- package/dist/resources/templates/go-backend/internal/common/providerconfig/schema.go +577 -0
- package/dist/resources/templates/go-backend/internal/common/providerconfig/schema_test.go +47 -0
- package/dist/resources/templates/go-backend/internal/common/requestprivacy/request.go +246 -0
- package/dist/resources/templates/go-backend/internal/common/requestprivacy/request_test.go +170 -0
- package/dist/resources/templates/go-backend/internal/common/response/pagination.go +60 -0
- package/dist/resources/templates/go-backend/internal/common/response/response.go +110 -0
- package/dist/resources/templates/go-backend/internal/common/response/response_test.go +463 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/ast.go +141 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/ast_test.go +81 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/canonical.go +184 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/canonical_test.go +319 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/decoder.go +555 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/decoder_test.go +260 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/errors.go +55 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/evaluator.go +96 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/evaluator_test.go +220 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/fuzz_test.go +116 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/limits.go +331 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/schema.go +412 -0
- package/dist/resources/templates/go-backend/internal/common/ruleexpression/schema_test.go +164 -0
- package/dist/resources/templates/go-backend/internal/common/runtimeinput/runtime_input.go +627 -0
- package/dist/resources/templates/go-backend/internal/common/runtimeinput/runtime_input_test.go +245 -0
- package/dist/resources/templates/go-backend/internal/common/semver/errors.go +6 -0
- package/dist/resources/templates/go-backend/internal/common/semver/semver.go +125 -0
- package/dist/resources/templates/go-backend/internal/common/semver/semver_test.go +205 -0
- package/dist/resources/templates/go-backend/internal/common/serviceidentity/audience.go +48 -0
- package/dist/resources/templates/go-backend/internal/common/serviceidentity/audience_test.go +35 -0
- package/dist/resources/templates/go-backend/internal/common/serviceidentity/resource_identifier.go +33 -0
- package/dist/resources/templates/go-backend/internal/common/serviceidentity/resource_identifier_test.go +32 -0
- package/dist/resources/templates/go-backend/internal/common/tradeno/generator.go +99 -0
- package/dist/resources/templates/go-backend/internal/common/tradeno/generator_test.go +396 -0
- package/dist/resources/templates/go-backend/internal/common/tradeno/prefix.go +247 -0
- package/dist/resources/templates/go-backend/internal/common/types/asset_url.go +11 -0
- package/dist/resources/templates/go-backend/internal/common/types/billing.go +89 -0
- package/dist/resources/templates/go-backend/internal/common/types/billing_test.go +77 -0
- package/dist/resources/templates/go-backend/internal/common/types/country.go +74 -0
- package/dist/resources/templates/go-backend/internal/common/types/country_test.go +28 -0
- package/dist/resources/templates/go-backend/internal/common/types/currency.go +60 -0
- package/dist/resources/templates/go-backend/internal/common/types/identifiers.go +41 -0
- package/dist/resources/templates/go-backend/internal/common/types/operator.go +28 -0
- package/dist/resources/templates/go-backend/internal/common/types/subscription_entitlement.go +24 -0
- package/dist/resources/templates/go-backend/internal/common/types/subscription_entitlement_test.go +35 -0
- package/dist/resources/templates/go-backend/internal/common/types/tier.go +72 -0
- package/dist/resources/templates/go-backend/internal/common/types/types.go +411 -0
- package/dist/resources/templates/go-backend/internal/common/types/types_test.go +295 -0
- package/dist/resources/templates/go-backend/internal/common/utils/constants.go +100 -0
- package/dist/resources/templates/go-backend/internal/common/utils/crypto.go +158 -0
- package/dist/resources/templates/go-backend/internal/common/utils/crypto_test.go +345 -0
- package/dist/resources/templates/go-backend/internal/common/utils/duration.go +25 -0
- package/dist/resources/templates/go-backend/internal/common/utils/helpers.go +18 -0
- package/dist/resources/templates/go-backend/internal/common/utils/json.go +62 -0
- package/dist/resources/templates/go-backend/internal/common/utils/json_test.go +76 -0
- package/dist/resources/templates/go-backend/internal/common/utils/pagination.go +51 -0
- package/dist/resources/templates/go-backend/internal/common/utils/pagination_test.go +45 -0
- package/dist/resources/templates/go-backend/internal/common/utils/pointer.go +107 -0
- package/dist/resources/templates/go-backend/internal/common/utils/pointer_test.go +15 -0
- package/dist/resources/templates/go-backend/internal/common/utils/slice.go +24 -0
- package/dist/resources/templates/go-backend/internal/common/utils/snowflake.go +110 -0
- package/dist/resources/templates/go-backend/internal/common/utils/snowflake_test.go +316 -0
- package/dist/resources/templates/go-backend/internal/common/utils/string.go +16 -0
- package/dist/resources/templates/go-backend/internal/common/utils/timefmt.go +42 -0
- package/dist/resources/templates/go-backend/internal/common/validator/validator.go +136 -0
- package/dist/resources/templates/go-backend/internal/common/validator/validator_test.go +240 -0
- package/dist/resources/templates/go-backend/internal/common/youtubeapi/client.go +224 -0
- package/dist/resources/templates/go-backend/internal/core/apicontract/document.go +269 -0
- package/dist/resources/templates/go-backend/internal/core/apicontract/document_test.go +104 -0
- package/dist/resources/templates/go-backend/internal/core/apicontract/route_validator.go +78 -0
- package/dist/resources/templates/go-backend/internal/core/apicontract/route_validator_test.go +108 -0
- package/dist/resources/templates/go-backend/internal/core/apidocs/assets/scalar-api-reference.js +2385 -0
- package/dist/resources/templates/go-backend/internal/core/apidocs/assets/scalar-api-reference.metadata.json +10 -0
- package/dist/resources/templates/go-backend/internal/core/apidocs/route.go +107 -0
- package/dist/resources/templates/go-backend/internal/core/apidocs/route_test.go +200 -0
- package/dist/resources/templates/go-backend/internal/core/apidocs/scalar.go +117 -0
- package/dist/resources/templates/go-backend/internal/core/apidocs/scalar_test.go +99 -0
- package/dist/resources/templates/go-backend/internal/core/audit/access_log_policy.go +91 -0
- package/dist/resources/templates/go-backend/internal/core/audit/access_log_policy_test.go +51 -0
- package/dist/resources/templates/go-backend/internal/core/audit/actor_resolver.go +36 -0
- package/dist/resources/templates/go-backend/internal/core/audit/constants.go +30 -0
- package/dist/resources/templates/go-backend/internal/core/audit/context.go +119 -0
- package/dist/resources/templates/go-backend/internal/core/audit/context_test.go +310 -0
- package/dist/resources/templates/go-backend/internal/core/audit/dto.go +468 -0
- package/dist/resources/templates/go-backend/internal/core/audit/dto_admin.go +172 -0
- package/dist/resources/templates/go-backend/internal/core/audit/enum.go +460 -0
- package/dist/resources/templates/go-backend/internal/core/audit/enum_test.go +314 -0
- package/dist/resources/templates/go-backend/internal/core/audit/errors.go +9 -0
- package/dist/resources/templates/go-backend/internal/core/audit/handler.go +568 -0
- package/dist/resources/templates/go-backend/internal/core/audit/listener.go +319 -0
- package/dist/resources/templates/go-backend/internal/core/audit/listener_test.go +98 -0
- package/dist/resources/templates/go-backend/internal/core/audit/middleware.go +669 -0
- package/dist/resources/templates/go-backend/internal/core/audit/middleware_test.go +268 -0
- package/dist/resources/templates/go-backend/internal/core/audit/model.go +306 -0
- package/dist/resources/templates/go-backend/internal/core/audit/partition_job.go +316 -0
- package/dist/resources/templates/go-backend/internal/core/audit/ports.go +9 -0
- package/dist/resources/templates/go-backend/internal/core/audit/provider.go +30 -0
- package/dist/resources/templates/go-backend/internal/core/audit/repository.go +1007 -0
- package/dist/resources/templates/go-backend/internal/core/audit/repository_test.go +934 -0
- package/dist/resources/templates/go-backend/internal/core/audit/router.go +85 -0
- package/dist/resources/templates/go-backend/internal/core/audit/service.go +770 -0
- package/dist/resources/templates/go-backend/internal/core/audit/service_test.go +331 -0
- package/dist/resources/templates/go-backend/internal/core/audit/vo_admin.go +475 -0
- package/dist/resources/templates/go-backend/internal/core/cache/config.go +30 -0
- package/dist/resources/templates/go-backend/internal/core/cache/key.go +41 -0
- package/dist/resources/templates/go-backend/internal/core/cache/key_test.go +62 -0
- package/dist/resources/templates/go-backend/internal/core/cache/l1.go +153 -0
- package/dist/resources/templates/go-backend/internal/core/cache/l1_test.go +212 -0
- package/dist/resources/templates/go-backend/internal/core/cache/manager.go +278 -0
- package/dist/resources/templates/go-backend/internal/core/cache/manager_provider.go +24 -0
- package/dist/resources/templates/go-backend/internal/core/cache/metrics.go +126 -0
- package/dist/resources/templates/go-backend/internal/core/cache/namespace.go +46 -0
- package/dist/resources/templates/go-backend/internal/core/cache/namespace_test.go +90 -0
- package/dist/resources/templates/go-backend/internal/core/cache/options.go +39 -0
- package/dist/resources/templates/go-backend/internal/core/cache/options_test.go +96 -0
- package/dist/resources/templates/go-backend/internal/core/cache/redis.go +311 -0
- package/dist/resources/templates/go-backend/internal/core/cache/redis_test.go +51 -0
- package/dist/resources/templates/go-backend/internal/core/cache/serializer.go +31 -0
- package/dist/resources/templates/go-backend/internal/core/cache/serializer_test.go +139 -0
- package/dist/resources/templates/go-backend/internal/core/cache/singleflight.go +53 -0
- package/dist/resources/templates/go-backend/internal/core/cache/singleflight_test.go +211 -0
- package/dist/resources/templates/go-backend/internal/core/cache/warming.go +86 -0
- package/dist/resources/templates/go-backend/internal/core/clock/clock.go +66 -0
- package/dist/resources/templates/go-backend/internal/core/clock/clock_test.go +26 -0
- package/dist/resources/templates/go-backend/internal/core/clock/runtime_clock.go +283 -0
- package/dist/resources/templates/go-backend/internal/core/clock/runtime_clock_test.go +98 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/errors.go +6 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/model.go +90 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/model_test.go +79 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/namespace.go +7 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/persistence.go +269 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/persistence_test.go +185 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/provider.go +9 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/repository.go +22 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/service.go +853 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/service_persistence_test.go +432 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/service_test.go +891 -0
- package/dist/resources/templates/go-backend/internal/core/commandreplay/types.go +121 -0
- package/dist/resources/templates/go-backend/internal/core/config/config.go +2069 -0
- package/dist/resources/templates/go-backend/internal/core/config/config_test.go +1122 -0
- package/dist/resources/templates/go-backend/internal/core/config/contract/contract_test.go +388 -0
- package/dist/resources/templates/go-backend/internal/core/config/contract/docs.go +198 -0
- package/dist/resources/templates/go-backend/internal/core/config/contract/verify.go +424 -0
- package/dist/resources/templates/go-backend/internal/core/config/enum.go +46 -0
- package/dist/resources/templates/go-backend/internal/core/config/metadata.go +717 -0
- package/dist/resources/templates/go-backend/internal/core/config/metadata_test.go +228 -0
- package/dist/resources/templates/go-backend/internal/core/config/product_admin_config_test.go +210 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/aes_gcm.go +111 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/aes_gcm_test.go +364 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/encryptor.go +12 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/envelope_encryptor.go +134 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/envelope_encryptor_test.go +118 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/pem.go +112 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/pem_test.go +44 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/provider.go +130 -0
- package/dist/resources/templates/go-backend/internal/core/crypto/provider_test.go +92 -0
- package/dist/resources/templates/go-backend/internal/core/database/base_model.go +24 -0
- package/dist/resources/templates/go-backend/internal/core/database/clickhouse.go +121 -0
- package/dist/resources/templates/go-backend/internal/core/database/database.go +112 -0
- package/dist/resources/templates/go-backend/internal/core/database/database_logger_test.go +95 -0
- package/dist/resources/templates/go-backend/internal/core/database/errors.go +25 -0
- package/dist/resources/templates/go-backend/internal/core/database/metrics_plugin.go +105 -0
- package/dist/resources/templates/go-backend/internal/core/database/pool_collector.go +71 -0
- package/dist/resources/templates/go-backend/internal/core/database/read_replica.go +520 -0
- package/dist/resources/templates/go-backend/internal/core/database/transaction.go +170 -0
- package/dist/resources/templates/go-backend/internal/core/database/transaction_test.go +282 -0
- package/dist/resources/templates/go-backend/internal/core/distlock/lock.go +353 -0
- package/dist/resources/templates/go-backend/internal/core/distlock/lock_test.go +106 -0
- package/dist/resources/templates/go-backend/internal/core/errors/handler.go +189 -0
- package/dist/resources/templates/go-backend/internal/core/errors/handler_test.go +515 -0
- package/dist/resources/templates/go-backend/internal/core/eventbus/eventbus.go +667 -0
- package/dist/resources/templates/go-backend/internal/core/eventbus/eventbus_test.go +792 -0
- package/dist/resources/templates/go-backend/internal/core/eventstream/noop.go +22 -0
- package/dist/resources/templates/go-backend/internal/core/eventstream/provider.go +20 -0
- package/dist/resources/templates/go-backend/internal/core/eventstream/publisher.go +38 -0
- package/dist/resources/templates/go-backend/internal/core/eventstream/redis.go +109 -0
- package/dist/resources/templates/go-backend/internal/core/eventstream/routing.go +104 -0
- package/dist/resources/templates/go-backend/internal/core/eventstream/routing_test.go +71 -0
- package/dist/resources/templates/go-backend/internal/core/geoip/model.go +19 -0
- package/dist/resources/templates/go-backend/internal/core/geoip/service.go +88 -0
- package/dist/resources/templates/go-backend/internal/core/health/health.go +333 -0
- package/dist/resources/templates/go-backend/internal/core/health/health_test.go +27 -0
- package/dist/resources/templates/go-backend/internal/core/httpclient/client.go +772 -0
- package/dist/resources/templates/go-backend/internal/core/httpclient/client_test.go +287 -0
- package/dist/resources/templates/go-backend/internal/core/httpclient/download.go +578 -0
- package/dist/resources/templates/go-backend/internal/core/httpclient/download_test.go +374 -0
- package/dist/resources/templates/go-backend/internal/core/jwtkeyring/jwk.go +38 -0
- package/dist/resources/templates/go-backend/internal/core/jwtkeyring/keyring.go +144 -0
- package/dist/resources/templates/go-backend/internal/core/jwtkeyring/keyring_test.go +128 -0
- package/dist/resources/templates/go-backend/internal/core/jwtkeyring/registry.go +60 -0
- package/dist/resources/templates/go-backend/internal/core/logger/logger.go +53 -0
- package/dist/resources/templates/go-backend/internal/core/logger/logger_test.go +194 -0
- package/dist/resources/templates/go-backend/internal/core/observability/metrics.go +358 -0
- package/dist/resources/templates/go-backend/internal/core/observability/sentry.go +445 -0
- package/dist/resources/templates/go-backend/internal/core/observability/sentry_privacy_test.go +175 -0
- package/dist/resources/templates/go-backend/internal/core/observability/tracing.go +187 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/model.go +314 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/model_test.go +77 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/persistence.go +51 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/provider.go +23 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/relay.go +1138 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/relay_postgres_test.go +257 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/relay_test.go +690 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/rescheduler.go +164 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/rescheduler_test.go +209 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/writer.go +249 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/writer_postgres_test.go +170 -0
- package/dist/resources/templates/go-backend/internal/core/outbox/writer_test.go +123 -0
- package/dist/resources/templates/go-backend/internal/core/provider.go +198 -0
- package/dist/resources/templates/go-backend/internal/core/queue/metrics_middleware.go +38 -0
- package/dist/resources/templates/go-backend/internal/core/queue/metrics_middleware_test.go +12 -0
- package/dist/resources/templates/go-backend/internal/core/queue/queue.go +288 -0
- package/dist/resources/templates/go-backend/internal/core/queue/queue_test.go +159 -0
- package/dist/resources/templates/go-backend/internal/core/resilience/bulkhead.go +514 -0
- package/dist/resources/templates/go-backend/internal/core/resilience/bulkhead_test.go +984 -0
- package/dist/resources/templates/go-backend/internal/core/resilience/circuitbreaker.go +358 -0
- package/dist/resources/templates/go-backend/internal/core/resilience/circuitbreaker_test.go +788 -0
- package/dist/resources/templates/go-backend/internal/core/resilience/retry.go +318 -0
- package/dist/resources/templates/go-backend/internal/core/resilience/retry_test.go +735 -0
- package/dist/resources/templates/go-backend/internal/core/schedule/recorder.go +305 -0
- package/dist/resources/templates/go-backend/internal/core/schedule/run_context.go +124 -0
- package/dist/resources/templates/go-backend/internal/core/schedule/run_context_test.go +85 -0
- package/dist/resources/templates/go-backend/internal/core/schedule/scheduler.go +1589 -0
- package/dist/resources/templates/go-backend/internal/core/schedule/scheduler_control_test.go +808 -0
- package/dist/resources/templates/go-backend/internal/core/storage/oss_provider.go +398 -0
- package/dist/resources/templates/go-backend/internal/core/storage/oss_provider_test.go +89 -0
- package/dist/resources/templates/go-backend/internal/core/storage/path.go +110 -0
- package/dist/resources/templates/go-backend/internal/core/storage/path_test.go +301 -0
- package/dist/resources/templates/go-backend/internal/core/storage/s3_provider.go +489 -0
- package/dist/resources/templates/go-backend/internal/core/storage/s3_provider_test.go +60 -0
- package/dist/resources/templates/go-backend/internal/core/storage/storage.go +268 -0
- package/dist/resources/templates/go-backend/internal/core/storage/validation.go +225 -0
- package/dist/resources/templates/go-backend/internal/core/storage/validation_test.go +495 -0
- package/dist/resources/templates/go-backend/internal/core/temporal/logger.go +38 -0
- package/dist/resources/templates/go-backend/internal/core/temporal/provider.go +126 -0
- package/dist/resources/templates/go-backend/internal/core/temporal/provider_test.go +67 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/client.go +282 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/client_test.go +81 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/config.go +58 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/handler.go +53 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/hub.go +269 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/message.go +273 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/notifier.go +92 -0
- package/dist/resources/templates/go-backend/internal/core/websocket/provider.go +33 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/action.go +77 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/action_test.go +238 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/condition.go +107 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/decision.go +256 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/enum.go +643 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/errors.go +102 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/principal_record.go +21 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/product_context.go +486 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/resource.go +215 -0
- package/dist/resources/templates/go-backend/internal/integrations/onex/iam/resource_test.go +242 -0
- package/dist/resources/templates/go-backend/internal/products/README.md +5 -0
- package/dist/resources/templates/go-backend/internal/sharedevents/README.md +5 -0
- package/dist/resources/templates/go-backend/migrations/000001_infrastructure.down.sql +13 -0
- package/dist/resources/templates/go-backend/migrations/000001_infrastructure.up.sql +886 -0
- package/dist/resources/templates/go-backend/pkg/apierror/error.go +327 -0
- package/dist/resources/templates/go-backend/pkg/apierror/error_code.go +65 -0
- package/dist/resources/templates/go-backend/pkg/apierror/error_test.go +41 -0
- package/dist/resources/templates/go-backend/pkg/apierror/error_type.go +14 -0
- package/dist/resources/templates/go-backend/pkg/apierror/http_response.go +216 -0
- package/dist/resources/templates/go-backend/pkg/apierror/http_response_test.go +216 -0
- package/dist/resources/templates/go-backend/scripts/check-openapi-clean-deletion.sh +54 -0
- package/dist/resources/templates/go-backend/scripts/test-migrations.sh +32 -0
- package/dist/resources/templates/go-backend/tests/infrastructure.sql +69 -0
- package/dist/resources/templates/mcp-server/.claude/docs/stack.md +338 -0
- package/dist/resources/templates/mcp-server/.editorconfig +13 -0
- package/dist/resources/templates/mcp-server/.env.example +8 -0
- package/dist/resources/templates/mcp-server/.github/ISSUE_TEMPLATE/bug_report.yml +104 -0
- package/dist/resources/templates/mcp-server/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
- package/dist/resources/templates/mcp-server/.github/PULL_REQUEST_TEMPLATE.md +36 -0
- package/dist/resources/templates/mcp-server/.github/workflows/ci.yml +78 -0
- package/dist/resources/templates/mcp-server/.husky/commit-msg +1 -0
- package/dist/resources/templates/mcp-server/.husky/pre-commit +1 -0
- package/dist/resources/templates/mcp-server/.lintstagedrc.json +4 -0
- package/dist/resources/templates/mcp-server/.nvmrc +1 -0
- package/dist/resources/templates/mcp-server/.prettierrc +8 -0
- package/dist/resources/templates/mcp-server/CONTRIBUTING.md +184 -0
- package/dist/resources/templates/mcp-server/Dockerfile +23 -0
- package/dist/resources/templates/mcp-server/LICENSE +21 -0
- package/dist/resources/templates/mcp-server/README.md +123 -0
- package/dist/resources/templates/mcp-server/_gitignore +26 -0
- package/dist/resources/templates/mcp-server/commitlint.config.js +24 -0
- package/dist/resources/templates/mcp-server/eslint.config.js +30 -0
- package/dist/resources/templates/mcp-server/package.json +72 -0
- package/dist/resources/templates/mcp-server/src/index.ts +27 -0
- package/dist/resources/templates/mcp-server/src/resources.ts +33 -0
- package/dist/resources/templates/mcp-server/src/services/.gitkeep +0 -0
- package/dist/resources/templates/mcp-server/src/tools.ts +43 -0
- package/dist/resources/templates/mcp-server/src/types/index.ts +19 -0
- package/dist/resources/templates/mcp-server/src/utils/index.ts +31 -0
- package/dist/resources/templates/mcp-server/tsconfig.json +22 -0
- package/dist/resources/templates/mcp-server/tsup.config.ts +14 -0
- package/dist/resources/templates/mcp-server/vitest.config.ts +15 -0
- package/dist/resources/templates/nuxt/.claude/docs/stack.md +666 -0
- package/dist/resources/templates/nuxt/.editorconfig +15 -0
- package/dist/resources/templates/nuxt/.env.example +22 -0
- package/dist/resources/templates/nuxt/.github/workflows/ci.yml +34 -0
- package/dist/resources/templates/nuxt/.husky/commit-msg +1 -0
- package/dist/resources/templates/nuxt/.husky/pre-commit +1 -0
- package/dist/resources/templates/nuxt/.nvmrc +1 -0
- package/dist/resources/templates/nuxt/.prettierignore +9 -0
- package/dist/resources/templates/nuxt/.prettierrc +1 -0
- package/dist/resources/templates/nuxt/README.md +23 -0
- package/dist/resources/templates/nuxt/_gitignore +7 -0
- package/dist/resources/templates/nuxt/app/app.config.ts +105 -0
- package/dist/resources/templates/nuxt/app/i18n/locales/en.json +5 -0
- package/dist/resources/templates/nuxt/app/pages/app/index.vue +224 -0
- package/dist/resources/templates/nuxt/app/pages/authors/[slug].vue +37 -0
- package/dist/resources/templates/nuxt/app/pages/blog/[slug].vue +55 -0
- package/dist/resources/templates/nuxt/app/pages/blog/category/[category].vue +38 -0
- package/dist/resources/templates/nuxt/app/pages/blog/index.vue +46 -0
- package/dist/resources/templates/nuxt/app/pages/index.vue +626 -0
- package/dist/resources/templates/nuxt/app/pages/legal/privacy.vue +21 -0
- package/dist/resources/templates/nuxt/app/pages/legal/terms.vue +21 -0
- package/dist/resources/templates/nuxt/app/pages/ui/index.vue +397 -0
- package/dist/resources/templates/nuxt/commitlint.config.mjs +1 -0
- package/dist/resources/templates/nuxt/eslint.config.mjs +4 -0
- package/dist/resources/templates/nuxt/lint-staged.config.mjs +8 -0
- package/dist/resources/templates/nuxt/nuxt.config.ts +71 -0
- package/dist/resources/templates/nuxt/package.json +67 -0
- package/dist/resources/templates/nuxt/public/apple-touch-icon.png +0 -0
- package/dist/resources/templates/nuxt/public/favicon.ico +0 -0
- package/dist/resources/templates/nuxt/public/favicon.svg +5 -0
- package/dist/resources/templates/nuxt/public/icon-16x16.png +0 -0
- package/dist/resources/templates/nuxt/public/icon-192x192.png +0 -0
- package/dist/resources/templates/nuxt/public/icon-32x32.png +0 -0
- package/dist/resources/templates/nuxt/public/icon-512x512.png +0 -0
- package/dist/resources/templates/nuxt/public/logo.svg +6 -0
- package/dist/resources/templates/nuxt/public/media/hero-product-gallery.png +0 -0
- package/dist/resources/templates/nuxt/server/api/content/sitemap-urls.get.ts +12 -0
- package/dist/resources/templates/nuxt/server/api/preview.get.ts +9 -0
- package/dist/resources/templates/nuxt/stylelint.config.mjs +3 -0
- package/dist/resources/templates/nuxt/test/e2e/rendering.test.ts +13 -0
- package/dist/resources/templates/nuxt/tsconfig.json +3 -0
- package/dist/resources/templates/nuxt/vitest.config.ts +8 -0
- package/package.json +8 -5
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
package domain
|
|
2
|
+
|
|
3
|
+
import "errors"
|
|
4
|
+
|
|
5
|
+
// ═══════════════════════════════════════════════════════════════
|
|
6
|
+
// IAM 授权内核 — 领域哨兵错误
|
|
7
|
+
// ═══════════════════════════════════════════════════════════════
|
|
8
|
+
//
|
|
9
|
+
// 仅定义存在实际调用路径的哨兵错误(H5:不投机预留);
|
|
10
|
+
// 错误消息使用英文(C4)。调用方用 errors.Is 判定,errors.Unwrap 取根因。
|
|
11
|
+
|
|
12
|
+
var (
|
|
13
|
+
// ErrInvalidResourceARN 资源 ARN 格式非法(段数 / 末段 type/id 切分不符合规范)。
|
|
14
|
+
ErrInvalidResourceARN = errors.New("iam: invalid resource ARN")
|
|
15
|
+
// ErrInvalidAction 动作格式非法(非 <domain>:<resource>:<verb> 三段或动词不在规范集合)。
|
|
16
|
+
ErrInvalidAction = errors.New("iam: invalid action")
|
|
17
|
+
// ErrPrincipalNotFound 认证身份未映射到活跃 IAM 主体(无主体 / 主体停用 / 已软删)。
|
|
18
|
+
ErrPrincipalNotFound = errors.New("iam: principal not found")
|
|
19
|
+
// ErrProductContextNotFound 产品注册表不存在指定产品。
|
|
20
|
+
ErrProductContextNotFound = errors.New("iam: product context not found")
|
|
21
|
+
// ErrProductContextInvalid 产品授权事实缺失、冲突或不完整。
|
|
22
|
+
ErrProductContextInvalid = errors.New("iam: product context invalid")
|
|
23
|
+
// ErrProductContextUnavailable 产品授权事实读取失败。
|
|
24
|
+
ErrProductContextUnavailable = errors.New("iam: product context unavailable")
|
|
25
|
+
// ErrCapabilityContextUnavailable 策略需要能力事实但请求未携带已解析快照。
|
|
26
|
+
ErrCapabilityContextUnavailable = errors.New("iam: capability context unavailable")
|
|
27
|
+
// ErrAdminAccessContextUnavailable 当前进程不能装配管理端授权上下文。
|
|
28
|
+
ErrAdminAccessContextUnavailable = errors.New("iam: admin access context unavailable")
|
|
29
|
+
// ErrAdminAccessContextInvalid 求值请求未使用权威工厂装配完整上下文。
|
|
30
|
+
ErrAdminAccessContextInvalid = errors.New("iam: admin access context invalid")
|
|
31
|
+
// ErrPolicyConditionInvalid 已发布策略包含无法执行的条件定义。
|
|
32
|
+
ErrPolicyConditionInvalid = errors.New("iam: policy condition invalid")
|
|
33
|
+
// ErrLastSuperAdmin 撤销绑定会导致平台不存在活跃的全局超级管理员。
|
|
34
|
+
ErrLastSuperAdmin = errors.New("iam: cannot revoke the last platform super admin role binding")
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
// IAM 控制台策略管理业务错误码(string ErrorCode,配合 pkg/apierror 构造 HTTP 响应,C5)。
|
|
38
|
+
//
|
|
39
|
+
// not-found 用 ResourceNotFound(404,由 apierror.NotFound 内置);以下为本域特有的
|
|
40
|
+
// 409(状态冲突 / 唯一冲突)与 422(业务规则)语义码,前端据码做差异化提示(设计 §8.2)。
|
|
41
|
+
const (
|
|
42
|
+
// ErrCodePolicyCodeConflict 策略编码已存在(创建时唯一冲突,映射 409)。
|
|
43
|
+
ErrCodePolicyCodeConflict = "iam_policy_code_conflict"
|
|
44
|
+
// ErrCodePolicyInvalidTransition 策略状态机非法流转(如对终态再流转,映射 409)。
|
|
45
|
+
ErrCodePolicyInvalidTransition = "iam_policy_invalid_transition"
|
|
46
|
+
// ErrCodePolicyNotEditable 策略已超出可编辑窗口(仅 latest draft 可改语句,映射 422)。
|
|
47
|
+
ErrCodePolicyNotEditable = "iam_policy_not_editable"
|
|
48
|
+
// ErrCodePolicySystemManaged 系统策略只读,普通管理员不可编辑或流转(映射 422)。
|
|
49
|
+
ErrCodePolicySystemManaged = "iam_policy_system_managed"
|
|
50
|
+
// ErrCodePolicyForkSourceInvalid fork 来源不是系统策略(映射 422)。
|
|
51
|
+
ErrCodePolicyForkSourceInvalid = "iam_policy_fork_source_invalid"
|
|
52
|
+
// ErrCodePrincipalIdentityConflict 主体身份冲突(同一 identity_id 已绑定活跃主体,映射 409)。
|
|
53
|
+
ErrCodePrincipalIdentityConflict = "iam_principal_identity_conflict"
|
|
54
|
+
// ErrCodePrincipalTypeInvalid 主体类型非法(映射 422)。
|
|
55
|
+
ErrCodePrincipalTypeInvalid = "iam_principal_type_invalid"
|
|
56
|
+
// ErrCodeRoleCodeConflict 角色编码已存在(创建时唯一冲突,映射 409)。
|
|
57
|
+
ErrCodeRoleCodeConflict = "iam_role_code_conflict"
|
|
58
|
+
// ErrCodeRoleSystemManaged 系统内置角色只读,普通管理员不可编辑(映射 422)。
|
|
59
|
+
ErrCodeRoleSystemManaged = "iam_role_system_managed"
|
|
60
|
+
// ErrCodeBindingTargetInvalid 绑定目标非法(principal/role/group 三选一未恰好命中一个,映射 422)。
|
|
61
|
+
ErrCodeBindingTargetInvalid = "iam_binding_target_invalid"
|
|
62
|
+
// ErrCodeBindingScopeInvalid 绑定作用域非法(隔离维度 scope_value 为空,映射 422)。
|
|
63
|
+
ErrCodeBindingScopeInvalid = "iam_binding_scope_invalid"
|
|
64
|
+
// ErrCodeBindingConflict 绑定已存在(同 owner+scope 重复,映射 409)。
|
|
65
|
+
ErrCodeBindingConflict = "iam_binding_conflict"
|
|
66
|
+
// ErrCodeBindingProtected 绑定由专属权威服务管理,通用管理入口不可变更(映射 422)。
|
|
67
|
+
ErrCodeBindingProtected = "iam_binding_protected"
|
|
68
|
+
// ErrCodeLastSuperAdmin 不可解绑最后一个 platform_super 角色绑定(管理护栏,映射 422)。
|
|
69
|
+
ErrCodeLastSuperAdmin = "iam_last_super_admin"
|
|
70
|
+
// ErrCodeGroupCodeConflict 组编码已存在(创建时唯一冲突,映射 409)。
|
|
71
|
+
ErrCodeGroupCodeConflict = "iam_group_code_conflict"
|
|
72
|
+
// ErrCodeGroupScopeInvalid 组作用域非法(隔离维度 scope_value 为空或 global 带值,映射 422)。
|
|
73
|
+
ErrCodeGroupScopeInvalid = "iam_group_scope_invalid"
|
|
74
|
+
// ErrCodeGroupSystemManaged 系统内置组只读,普通管理员不可编辑或删除(映射 422)。
|
|
75
|
+
ErrCodeGroupSystemManaged = "iam_group_system_managed"
|
|
76
|
+
// ErrCodeGroupDeleteBlocked 用户组仍有活跃成员或策略绑定,不允许删除(映射 422)。
|
|
77
|
+
ErrCodeGroupDeleteBlocked = "iam_group_delete_blocked"
|
|
78
|
+
// ErrCodeGroupMemberConflict 组成员已存在(同 group+principal 重复,映射 409)。
|
|
79
|
+
ErrCodeGroupMemberConflict = "iam_group_member_conflict"
|
|
80
|
+
// ErrCodePageActionConflict 页面动作契约已存在(同 page_key+action_key 重复,映射 409)。
|
|
81
|
+
ErrCodePageActionConflict = "iam_page_action_conflict"
|
|
82
|
+
// ErrCodePageActionInvalid 页面动作契约字段非法(placement / risk / audit 取值不合法,映射 422)。
|
|
83
|
+
ErrCodePageActionInvalid = "iam_page_action_invalid"
|
|
84
|
+
// ErrCodeFieldRuleConflict 字段脱敏规则已存在(同 resource_type+field_key 重复,映射 409)。
|
|
85
|
+
ErrCodeFieldRuleConflict = "iam_field_rule_conflict"
|
|
86
|
+
// ErrCodeFieldRuleInvalid 字段脱敏规则字段非法(sensitivity / masking_strategy 取值不合法,映射 422)。
|
|
87
|
+
ErrCodeFieldRuleInvalid = "iam_field_rule_invalid"
|
|
88
|
+
// ErrCodeCredentialPrincipalInvalid 凭证归属主体非法(主体不存在 / 非 service_account 类型,映射 422)。
|
|
89
|
+
ErrCodeCredentialPrincipalInvalid = "iam_credential_principal_invalid" //nolint:gosec // G101: 错误码常量,非凭据
|
|
90
|
+
// ErrCodeServiceAccountDeleteBlocked 服务账号仍处于启用状态或存在依赖资源,不允许删除(映射 422)。
|
|
91
|
+
ErrCodeServiceAccountDeleteBlocked = "iam_service_account_delete_blocked"
|
|
92
|
+
// ErrCodeCredentialDeleteBlocked 凭证仍处于启用状态,不允许删除(映射 422)。
|
|
93
|
+
ErrCodeCredentialDeleteBlocked = "iam_credential_delete_blocked" //nolint:gosec // G101: 错误码常量,非凭据
|
|
94
|
+
// ErrCodeCredentialExpiresInvalid 凭证过期时间非法(早于当前时间,映射 422)。
|
|
95
|
+
ErrCodeCredentialExpiresInvalid = "iam_credential_expires_invalid" //nolint:gosec // G101: 错误码常量,非凭据
|
|
96
|
+
// ErrCodeCredentialRevoked 凭证已吊销,不可再吊销 / 轮换(终态,映射 422)。
|
|
97
|
+
ErrCodeCredentialRevoked = "iam_credential_revoked" //nolint:gosec // G101: 错误码常量,非凭据
|
|
98
|
+
// ErrCodeCredentialAuthenticationRejected 服务账号凭证认证失败(映射 401,不暴露具体失败原因)。
|
|
99
|
+
ErrCodeCredentialAuthenticationRejected = "iam_credential_authentication_rejected" //nolint:gosec // G101: 错误码常量,非凭据
|
|
100
|
+
// ErrCodeCredentialAuthorizationRejected 服务账号凭证授权失败(映射 403,不暴露具体失败原因)。
|
|
101
|
+
ErrCodeCredentialAuthorizationRejected = "iam_credential_authorization_rejected" //nolint:gosec // G101: 错误码常量,非凭据
|
|
102
|
+
)
|
package/dist/resources/templates/go-backend/internal/integrations/onex/iam/principal_record.go
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
package domain
|
|
2
|
+
|
|
3
|
+
// PrincipalRecord IAM 主体解析结果(授权上下文所需的主体维度)。
|
|
4
|
+
//
|
|
5
|
+
// 是 Principal 实体投影的值对象:ID 为 IAM 主体主键(binding 表 principal_id 指向它),
|
|
6
|
+
// IdentityID 才是关联的认证身份;二者语义不同不可混用(SH-I1)。隔离维度
|
|
7
|
+
// (organization/merchant/tenant/agent)随主体携带,供求值器装配 PrincipalContext。
|
|
8
|
+
type PrincipalRecord struct {
|
|
9
|
+
// IAM 主体主键(role/group/policy binding 的 principal_id 指向它)
|
|
10
|
+
ID int64
|
|
11
|
+
// 不可变主体公共引用。
|
|
12
|
+
PrincipalNo string
|
|
13
|
+
// 主体类型(见 enum.go PrincipalType,对应 condition principal_type)
|
|
14
|
+
PrincipalType string
|
|
15
|
+
// 关联认证身份 ID(human_user)。
|
|
16
|
+
IdentityID *int64
|
|
17
|
+
// 是否启用(停用主体所有授权立即失效)
|
|
18
|
+
IsActive bool
|
|
19
|
+
// 主体聚合版本。
|
|
20
|
+
Version int64
|
|
21
|
+
}
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
package domain
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"errors"
|
|
7
|
+
"fmt"
|
|
8
|
+
"sort"
|
|
9
|
+
"strings"
|
|
10
|
+
"time"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
const productKindAttributeCode = "product_kind"
|
|
14
|
+
|
|
15
|
+
// ProductAttributeFact 是 IAM 所需的单个产品属性事实。
|
|
16
|
+
//
|
|
17
|
+
// Value 为 nil 表示目录已知但当前没有生效值,以区分未知属性。
|
|
18
|
+
type ProductAttributeFact struct {
|
|
19
|
+
// 属性编码
|
|
20
|
+
Code string
|
|
21
|
+
// 经产品所有者校验的 canonical JSON 值
|
|
22
|
+
Value json.RawMessage
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ProductCapabilityFact 产品授权所需的单个能力事实。
|
|
26
|
+
type ProductCapabilityFact struct {
|
|
27
|
+
// 能力编码
|
|
28
|
+
Code string
|
|
29
|
+
// 是否在当前产品上下文中生效
|
|
30
|
+
Active bool
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ProductContextSnapshot 产品所有者投影给 IAM 的可信事实快照。
|
|
34
|
+
//
|
|
35
|
+
// Capabilities 非 nil 表示能力目录事实已经完整解析;空切片表示目录中没有能力事实。
|
|
36
|
+
type ProductContextSnapshot struct {
|
|
37
|
+
// 产品编码
|
|
38
|
+
ProductCode string
|
|
39
|
+
// 产品形态,必须与 product_kind 属性一致
|
|
40
|
+
ProductKind string
|
|
41
|
+
// 产品生命周期状态
|
|
42
|
+
LifecycleStatus string
|
|
43
|
+
// 产品上下文单调写版本
|
|
44
|
+
ContextVersion int64
|
|
45
|
+
// 当前有效事实的 canonical 指纹
|
|
46
|
+
ContextFingerprint string
|
|
47
|
+
// 产品属性事实
|
|
48
|
+
Attributes []ProductAttributeFact
|
|
49
|
+
// 产品能力事实
|
|
50
|
+
Capabilities []ProductCapabilityFact
|
|
51
|
+
// 快照解析时刻
|
|
52
|
+
ResolvedAt time.Time
|
|
53
|
+
// 快照必须重新解析的最近边界
|
|
54
|
+
ExpiresAt *time.Time
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ProductAuthorizationContextReader 读取 IAM 所需的产品授权事实。
|
|
58
|
+
//
|
|
59
|
+
// 接口由 IAM 消费方定义;产品模块 Adapter 只投影该窄契约,不暴露产品仓储或数据库模型。
|
|
60
|
+
type ProductAuthorizationContextReader interface {
|
|
61
|
+
ReadProductContextAt(ctx context.Context, productCode string, resolvedAt time.Time) (ProductContextSnapshot, error)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ProductContext 是 IAM 求值器消费的不可变产品维度投影。
|
|
65
|
+
type ProductContext struct {
|
|
66
|
+
// 产品编码
|
|
67
|
+
ProductCode string
|
|
68
|
+
// 产品形态
|
|
69
|
+
ProductKind string
|
|
70
|
+
// 生效能力编码集合
|
|
71
|
+
Capabilities []string
|
|
72
|
+
// 已解析的能力目录事实
|
|
73
|
+
CapabilityFacts []ProductCapabilityFact
|
|
74
|
+
// 已解析的属性目录事实
|
|
75
|
+
AttributeFacts []ProductAttributeFact
|
|
76
|
+
// 产品生命周期状态
|
|
77
|
+
LifecycleStatus string
|
|
78
|
+
// 产品上下文单调写版本
|
|
79
|
+
ContextVersion int64
|
|
80
|
+
// 当前有效事实的 canonical 指纹
|
|
81
|
+
ContextFingerprint string
|
|
82
|
+
// 快照解析时刻
|
|
83
|
+
ResolvedAt time.Time
|
|
84
|
+
// 快照必须重新解析的最近边界
|
|
85
|
+
ExpiresAt *time.Time
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type productContextSnapshotKey struct{}
|
|
89
|
+
|
|
90
|
+
// ResolveProductContextSnapshot 读取并规范化指定产品的可信授权事实。
|
|
91
|
+
func ResolveProductContextSnapshot(
|
|
92
|
+
ctx context.Context,
|
|
93
|
+
reader ProductAuthorizationContextReader,
|
|
94
|
+
productCode string,
|
|
95
|
+
resolvedAt time.Time,
|
|
96
|
+
) (ProductContextSnapshot, error) {
|
|
97
|
+
productCode = strings.TrimSpace(productCode)
|
|
98
|
+
if productCode == "" {
|
|
99
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: product code is required", ErrProductContextInvalid)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if reader == nil {
|
|
103
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: product context reader is not configured", ErrProductContextUnavailable)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
snapshot, err := reader.ReadProductContextAt(ctx, productCode, resolvedAt)
|
|
107
|
+
if err != nil {
|
|
108
|
+
switch {
|
|
109
|
+
case errors.Is(err, ErrProductContextNotFound):
|
|
110
|
+
return ProductContextSnapshot{}, fmt.Errorf("resolve product context %q: %w", productCode, err)
|
|
111
|
+
case errors.Is(err, ErrProductContextInvalid), errors.Is(err, ErrProductContextUnavailable):
|
|
112
|
+
return ProductContextSnapshot{}, fmt.Errorf("resolve product context %q: %w", productCode, err)
|
|
113
|
+
default:
|
|
114
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: resolve product context %q: %v", ErrProductContextUnavailable, productCode, err)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
normalized, err := snapshot.normalizedFor(productCode)
|
|
118
|
+
if err != nil {
|
|
119
|
+
return ProductContextSnapshot{}, err
|
|
120
|
+
}
|
|
121
|
+
if err := normalized.ValidateAt(resolvedAt); err != nil {
|
|
122
|
+
return ProductContextSnapshot{}, err
|
|
123
|
+
}
|
|
124
|
+
return normalized, nil
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ContextWithProductContextSnapshot 将已规范化快照绑定到当前请求,保证后续 IAM 装配校验并复用同一事实版本。
|
|
128
|
+
func ContextWithProductContextSnapshot(ctx context.Context, snapshot ProductContextSnapshot) context.Context {
|
|
129
|
+
return context.WithValue(ctx, productContextSnapshotKey{}, snapshot.clone())
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ProductContextSnapshotFromContext 读取当前请求已校验的产品事实快照。
|
|
133
|
+
func ProductContextSnapshotFromContext(ctx context.Context) (ProductContextSnapshot, bool) {
|
|
134
|
+
snapshot, ok := ctx.Value(productContextSnapshotKey{}).(ProductContextSnapshot)
|
|
135
|
+
if !ok {
|
|
136
|
+
return ProductContextSnapshot{}, false
|
|
137
|
+
}
|
|
138
|
+
return snapshot.clone(), true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ActiveCapabilityCodes 返回去重且稳定排序的生效能力编码。
|
|
142
|
+
func (s ProductContextSnapshot) ActiveCapabilityCodes() []string {
|
|
143
|
+
codes := make([]string, 0, len(s.Capabilities))
|
|
144
|
+
for i := range s.Capabilities {
|
|
145
|
+
if s.Capabilities[i].Active {
|
|
146
|
+
codes = append(codes, s.Capabilities[i].Code)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return codes
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ValidateAt 校验快照可在指定时刻进入请求上下文。
|
|
153
|
+
func (s ProductContextSnapshot) ValidateAt(now time.Time) error {
|
|
154
|
+
if now.IsZero() {
|
|
155
|
+
return productContextInvalid(s.ProductCode, "validation time is required")
|
|
156
|
+
}
|
|
157
|
+
if s.ContextVersion <= 0 {
|
|
158
|
+
return productContextInvalid(s.ProductCode, "context version must be positive")
|
|
159
|
+
}
|
|
160
|
+
if !isLowerHexSHA256(s.ContextFingerprint) {
|
|
161
|
+
return productContextInvalid(s.ProductCode, "context fingerprint must be a lowercase SHA-256 value")
|
|
162
|
+
}
|
|
163
|
+
if s.ResolvedAt.IsZero() {
|
|
164
|
+
return productContextInvalid(s.ProductCode, "resolved time is required")
|
|
165
|
+
}
|
|
166
|
+
if s.ResolvedAt.After(now) {
|
|
167
|
+
return productContextInvalid(s.ProductCode, "resolved time must not be in the future")
|
|
168
|
+
}
|
|
169
|
+
if s.Attributes == nil {
|
|
170
|
+
return productContextInvalid(s.ProductCode, "attribute facts are unresolved")
|
|
171
|
+
}
|
|
172
|
+
if s.Capabilities == nil {
|
|
173
|
+
return productContextInvalid(s.ProductCode, "capability facts are unresolved")
|
|
174
|
+
}
|
|
175
|
+
if s.ExpiresAt != nil {
|
|
176
|
+
if !s.ExpiresAt.After(s.ResolvedAt) {
|
|
177
|
+
return productContextInvalid(s.ProductCode, "expiry must be after resolved time")
|
|
178
|
+
}
|
|
179
|
+
if !now.Before(*s.ExpiresAt) {
|
|
180
|
+
return productContextInvalid(s.ProductCode, "product context snapshot is expired")
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
productKind, err := s.productKind()
|
|
185
|
+
if err != nil {
|
|
186
|
+
return err
|
|
187
|
+
}
|
|
188
|
+
if s.ProductKind != "" && s.ProductKind != productKind {
|
|
189
|
+
return productContextInvalid(s.ProductCode, "product kind projection does not match product_kind attribute")
|
|
190
|
+
}
|
|
191
|
+
return nil
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// AuthorizationContext 校验完整版本事实并投影为 IAM 产品上下文。
|
|
195
|
+
func (s ProductContextSnapshot) AuthorizationContext(now time.Time) (ProductContext, error) {
|
|
196
|
+
if err := s.ValidateAt(now); err != nil {
|
|
197
|
+
return ProductContext{}, err
|
|
198
|
+
}
|
|
199
|
+
productKind, _ := s.productKind()
|
|
200
|
+
|
|
201
|
+
return ProductContext{
|
|
202
|
+
ProductCode: s.ProductCode,
|
|
203
|
+
ProductKind: productKind,
|
|
204
|
+
Capabilities: s.ActiveCapabilityCodes(),
|
|
205
|
+
CapabilityFacts: cloneCapabilityFacts(s.Capabilities),
|
|
206
|
+
AttributeFacts: cloneAttributeFacts(s.Attributes),
|
|
207
|
+
LifecycleStatus: s.LifecycleStatus,
|
|
208
|
+
ContextVersion: s.ContextVersion,
|
|
209
|
+
ContextFingerprint: s.ContextFingerprint,
|
|
210
|
+
ResolvedAt: s.ResolvedAt,
|
|
211
|
+
ExpiresAt: cloneTime(s.ExpiresAt),
|
|
212
|
+
}, nil
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ValidateForWorkspace 验证 IAM 求值器收到的产品投影来自完整快照。
|
|
216
|
+
func (c ProductContext) ValidateForWorkspace(productCode string, now time.Time) error {
|
|
217
|
+
productCode = strings.TrimSpace(productCode)
|
|
218
|
+
if productCode == "" {
|
|
219
|
+
if c.ProductCode != "" || c.ProductKind != "" || c.LifecycleStatus != "" ||
|
|
220
|
+
c.ContextVersion != 0 || c.ContextFingerprint != "" || !c.ResolvedAt.IsZero() ||
|
|
221
|
+
c.ExpiresAt != nil || c.AttributeFacts != nil || c.CapabilityFacts != nil || c.Capabilities != nil {
|
|
222
|
+
return productContextInvalid(c.ProductCode, "platform-global workspace must not carry product facts")
|
|
223
|
+
}
|
|
224
|
+
return nil
|
|
225
|
+
}
|
|
226
|
+
if c.ProductCode != productCode {
|
|
227
|
+
return productContextInvalid(productCode, "workspace product does not match product context")
|
|
228
|
+
}
|
|
229
|
+
if c.ProductKind == "" || c.LifecycleStatus == "" || c.ContextVersion <= 0 ||
|
|
230
|
+
!isLowerHexSHA256(c.ContextFingerprint) || c.ResolvedAt.IsZero() ||
|
|
231
|
+
c.AttributeFacts == nil || c.CapabilityFacts == nil || c.Capabilities == nil {
|
|
232
|
+
return productContextInvalid(productCode, "authorization product context is incomplete")
|
|
233
|
+
}
|
|
234
|
+
if c.LifecycleStatus != strings.TrimSpace(c.LifecycleStatus) {
|
|
235
|
+
return productContextInvalid(productCode, "authorization product context is not canonical")
|
|
236
|
+
}
|
|
237
|
+
if c.ResolvedAt.After(now) {
|
|
238
|
+
return productContextInvalid(productCode, "authorization product context resolved time is in the future")
|
|
239
|
+
}
|
|
240
|
+
if c.ExpiresAt != nil && !c.ExpiresAt.After(c.ResolvedAt) {
|
|
241
|
+
return productContextInvalid(productCode, "authorization product context expiry is invalid")
|
|
242
|
+
}
|
|
243
|
+
if c.ExpiresAt != nil && !now.Before(*c.ExpiresAt) {
|
|
244
|
+
return productContextInvalid(productCode, "authorization product context is expired")
|
|
245
|
+
}
|
|
246
|
+
if err := c.validateFacts(); err != nil {
|
|
247
|
+
return err
|
|
248
|
+
}
|
|
249
|
+
return nil
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// HasCapability 判断产品上下文是否包含指定生效能力。
|
|
253
|
+
func (c ProductContext) HasCapability(code string) bool {
|
|
254
|
+
code = strings.TrimSpace(code)
|
|
255
|
+
if code == "" || c.Capabilities == nil {
|
|
256
|
+
return false
|
|
257
|
+
}
|
|
258
|
+
index := sort.SearchStrings(c.Capabilities, code)
|
|
259
|
+
return index < len(c.Capabilities) && c.Capabilities[index] == code
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// CapabilityState 返回能力是否生效以及该编码是否存在于目录事实。
|
|
263
|
+
func (c ProductContext) CapabilityState(code string) (active bool, known bool) {
|
|
264
|
+
code = strings.TrimSpace(code)
|
|
265
|
+
if code == "" || c.CapabilityFacts == nil {
|
|
266
|
+
return false, false
|
|
267
|
+
}
|
|
268
|
+
index := sort.Search(len(c.CapabilityFacts), func(i int) bool {
|
|
269
|
+
return c.CapabilityFacts[i].Code >= code
|
|
270
|
+
})
|
|
271
|
+
if index >= len(c.CapabilityFacts) || c.CapabilityFacts[index].Code != code {
|
|
272
|
+
return false, false
|
|
273
|
+
}
|
|
274
|
+
return c.CapabilityFacts[index].Active, true
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// AttributeFact 返回属性目录事实及当前是否存在生效值。
|
|
278
|
+
func (c ProductContext) AttributeFact(code string) (json.RawMessage, bool, bool) {
|
|
279
|
+
code = strings.TrimSpace(code)
|
|
280
|
+
if code == "" || c.AttributeFacts == nil {
|
|
281
|
+
return nil, false, false
|
|
282
|
+
}
|
|
283
|
+
index := sort.Search(len(c.AttributeFacts), func(i int) bool {
|
|
284
|
+
return c.AttributeFacts[i].Code >= code
|
|
285
|
+
})
|
|
286
|
+
if index >= len(c.AttributeFacts) || c.AttributeFacts[index].Code != code {
|
|
287
|
+
return nil, false, false
|
|
288
|
+
}
|
|
289
|
+
if c.AttributeFacts[index].Value == nil {
|
|
290
|
+
return nil, true, false
|
|
291
|
+
}
|
|
292
|
+
return cloneJSON(c.AttributeFacts[index].Value), true, true
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
func (c ProductContext) validateFacts() error {
|
|
296
|
+
activeCodes := make([]string, 0, len(c.CapabilityFacts))
|
|
297
|
+
for i := range c.CapabilityFacts {
|
|
298
|
+
if c.CapabilityFacts[i].Code == "" || c.CapabilityFacts[i].Code != strings.TrimSpace(c.CapabilityFacts[i].Code) ||
|
|
299
|
+
(i > 0 && c.CapabilityFacts[i-1].Code >= c.CapabilityFacts[i].Code) {
|
|
300
|
+
return productContextInvalid(c.ProductCode, "capability facts are not canonical")
|
|
301
|
+
}
|
|
302
|
+
if c.CapabilityFacts[i].Active {
|
|
303
|
+
activeCodes = append(activeCodes, c.CapabilityFacts[i].Code)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if len(activeCodes) != len(c.Capabilities) {
|
|
307
|
+
return productContextInvalid(c.ProductCode, "active capability projection is inconsistent")
|
|
308
|
+
}
|
|
309
|
+
for i := range activeCodes {
|
|
310
|
+
if activeCodes[i] != c.Capabilities[i] {
|
|
311
|
+
return productContextInvalid(c.ProductCode, "active capability projection is inconsistent")
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
productKind := ""
|
|
316
|
+
for i := range c.AttributeFacts {
|
|
317
|
+
if c.AttributeFacts[i].Code == "" || c.AttributeFacts[i].Code != strings.TrimSpace(c.AttributeFacts[i].Code) ||
|
|
318
|
+
(i > 0 && c.AttributeFacts[i-1].Code >= c.AttributeFacts[i].Code) {
|
|
319
|
+
return productContextInvalid(c.ProductCode, "attribute facts are not canonical")
|
|
320
|
+
}
|
|
321
|
+
if c.AttributeFacts[i].Value != nil && !json.Valid(c.AttributeFacts[i].Value) {
|
|
322
|
+
return productContextInvalid(c.ProductCode, "attribute fact contains invalid JSON")
|
|
323
|
+
}
|
|
324
|
+
if c.AttributeFacts[i].Code != productKindAttributeCode || c.AttributeFacts[i].Value == nil {
|
|
325
|
+
continue
|
|
326
|
+
}
|
|
327
|
+
if err := json.Unmarshal(c.AttributeFacts[i].Value, &productKind); err != nil {
|
|
328
|
+
return productContextInvalid(c.ProductCode, "product_kind attribute must be a string")
|
|
329
|
+
}
|
|
330
|
+
productKind = strings.TrimSpace(productKind)
|
|
331
|
+
}
|
|
332
|
+
if productKind == "" || productKind != c.ProductKind {
|
|
333
|
+
return productContextInvalid(c.ProductCode, "product kind projection is inconsistent")
|
|
334
|
+
}
|
|
335
|
+
return nil
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
func (s ProductContextSnapshot) normalizedFor(productCode string) (ProductContextSnapshot, error) {
|
|
339
|
+
s.ProductCode = strings.TrimSpace(s.ProductCode)
|
|
340
|
+
s.ProductKind = strings.TrimSpace(s.ProductKind)
|
|
341
|
+
s.LifecycleStatus = strings.TrimSpace(s.LifecycleStatus)
|
|
342
|
+
s.ContextFingerprint = strings.TrimSpace(s.ContextFingerprint)
|
|
343
|
+
if s.ProductCode != productCode {
|
|
344
|
+
return ProductContextSnapshot{}, fmt.Errorf(
|
|
345
|
+
"%w: requested product %q but reader returned %q",
|
|
346
|
+
ErrProductContextInvalid,
|
|
347
|
+
productCode,
|
|
348
|
+
s.ProductCode,
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
if s.LifecycleStatus == "" {
|
|
352
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: product %q has no lifecycle status", ErrProductContextInvalid, productCode)
|
|
353
|
+
}
|
|
354
|
+
if s.Capabilities == nil {
|
|
355
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: product %q capabilities are unresolved", ErrProductContextInvalid, productCode)
|
|
356
|
+
}
|
|
357
|
+
if s.ContextVersion < 0 {
|
|
358
|
+
return ProductContextSnapshot{}, productContextInvalid(productCode, "context version must not be negative")
|
|
359
|
+
}
|
|
360
|
+
if s.ContextFingerprint != "" && !isLowerHexSHA256(s.ContextFingerprint) {
|
|
361
|
+
return ProductContextSnapshot{}, productContextInvalid(productCode, "context fingerprint must be a lowercase SHA-256 value")
|
|
362
|
+
}
|
|
363
|
+
if s.ExpiresAt != nil && !s.ResolvedAt.IsZero() && !s.ExpiresAt.After(s.ResolvedAt) {
|
|
364
|
+
return ProductContextSnapshot{}, productContextInvalid(productCode, "expiry must be after resolved time")
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if s.Attributes != nil {
|
|
368
|
+
attributes := make([]ProductAttributeFact, len(s.Attributes))
|
|
369
|
+
seenAttributes := make(map[string]struct{}, len(s.Attributes))
|
|
370
|
+
for i := range s.Attributes {
|
|
371
|
+
code := strings.TrimSpace(s.Attributes[i].Code)
|
|
372
|
+
if code == "" {
|
|
373
|
+
return ProductContextSnapshot{}, productContextInvalid(productCode, "attribute code must not be empty")
|
|
374
|
+
}
|
|
375
|
+
if _, exists := seenAttributes[code]; exists {
|
|
376
|
+
return ProductContextSnapshot{}, productContextInvalid(productCode, "attribute facts contain duplicate codes")
|
|
377
|
+
}
|
|
378
|
+
seenAttributes[code] = struct{}{}
|
|
379
|
+
value := cloneJSON(s.Attributes[i].Value)
|
|
380
|
+
if value != nil && !json.Valid(value) {
|
|
381
|
+
return ProductContextSnapshot{}, productContextInvalid(productCode, "attribute fact contains invalid JSON")
|
|
382
|
+
}
|
|
383
|
+
attributes[i] = ProductAttributeFact{Code: code, Value: value}
|
|
384
|
+
}
|
|
385
|
+
sort.Slice(attributes, func(i, j int) bool { return attributes[i].Code < attributes[j].Code })
|
|
386
|
+
s.Attributes = attributes
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
capabilities := make([]ProductCapabilityFact, len(s.Capabilities))
|
|
390
|
+
seen := make(map[string]struct{}, len(s.Capabilities))
|
|
391
|
+
for i := range s.Capabilities {
|
|
392
|
+
code := strings.TrimSpace(s.Capabilities[i].Code)
|
|
393
|
+
if code == "" {
|
|
394
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: product %q contains an empty capability code", ErrProductContextInvalid, productCode)
|
|
395
|
+
}
|
|
396
|
+
if _, exists := seen[code]; exists {
|
|
397
|
+
return ProductContextSnapshot{}, fmt.Errorf("%w: product %q contains duplicate capability %q", ErrProductContextInvalid, productCode, code)
|
|
398
|
+
}
|
|
399
|
+
seen[code] = struct{}{}
|
|
400
|
+
capabilities[i] = ProductCapabilityFact{Code: code, Active: s.Capabilities[i].Active}
|
|
401
|
+
}
|
|
402
|
+
sort.Slice(capabilities, func(i, j int) bool {
|
|
403
|
+
return capabilities[i].Code < capabilities[j].Code
|
|
404
|
+
})
|
|
405
|
+
s.Capabilities = capabilities
|
|
406
|
+
s.ResolvedAt = s.ResolvedAt.UTC()
|
|
407
|
+
s.ExpiresAt = cloneTime(s.ExpiresAt)
|
|
408
|
+
return s, nil
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
func (s ProductContextSnapshot) clone() ProductContextSnapshot {
|
|
412
|
+
cloned := s
|
|
413
|
+
cloned.Attributes = cloneAttributeFacts(s.Attributes)
|
|
414
|
+
cloned.Capabilities = cloneCapabilityFacts(s.Capabilities)
|
|
415
|
+
cloned.ExpiresAt = cloneTime(s.ExpiresAt)
|
|
416
|
+
return cloned
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
func (s ProductContextSnapshot) productKind() (string, error) {
|
|
420
|
+
index := sort.Search(len(s.Attributes), func(i int) bool {
|
|
421
|
+
return s.Attributes[i].Code >= productKindAttributeCode
|
|
422
|
+
})
|
|
423
|
+
if index >= len(s.Attributes) || s.Attributes[index].Code != productKindAttributeCode || s.Attributes[index].Value == nil {
|
|
424
|
+
return "", productContextInvalid(s.ProductCode, "product_kind attribute is required")
|
|
425
|
+
}
|
|
426
|
+
var productKind string
|
|
427
|
+
if err := json.Unmarshal(s.Attributes[index].Value, &productKind); err != nil {
|
|
428
|
+
return "", productContextInvalid(s.ProductCode, "product_kind attribute must be a string")
|
|
429
|
+
}
|
|
430
|
+
productKind = strings.TrimSpace(productKind)
|
|
431
|
+
if productKind == "" {
|
|
432
|
+
return "", productContextInvalid(s.ProductCode, "product_kind attribute must not be empty")
|
|
433
|
+
}
|
|
434
|
+
return productKind, nil
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
func productContextInvalid(productCode string, reason string) error {
|
|
438
|
+
return fmt.Errorf("%w: product %q %s", ErrProductContextInvalid, productCode, reason)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
func cloneAttributeFacts(facts []ProductAttributeFact) []ProductAttributeFact {
|
|
442
|
+
if facts == nil {
|
|
443
|
+
return nil
|
|
444
|
+
}
|
|
445
|
+
cloned := make([]ProductAttributeFact, len(facts))
|
|
446
|
+
for i := range facts {
|
|
447
|
+
cloned[i] = ProductAttributeFact{Code: facts[i].Code, Value: cloneJSON(facts[i].Value)}
|
|
448
|
+
}
|
|
449
|
+
return cloned
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
func cloneCapabilityFacts(facts []ProductCapabilityFact) []ProductCapabilityFact {
|
|
453
|
+
if facts == nil {
|
|
454
|
+
return nil
|
|
455
|
+
}
|
|
456
|
+
cloned := make([]ProductCapabilityFact, len(facts))
|
|
457
|
+
copy(cloned, facts)
|
|
458
|
+
return cloned
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
func cloneJSON(value json.RawMessage) json.RawMessage {
|
|
462
|
+
if value == nil {
|
|
463
|
+
return nil
|
|
464
|
+
}
|
|
465
|
+
return append(json.RawMessage(nil), value...)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
func cloneTime(value *time.Time) *time.Time {
|
|
469
|
+
if value == nil {
|
|
470
|
+
return nil
|
|
471
|
+
}
|
|
472
|
+
cloned := value.UTC()
|
|
473
|
+
return &cloned
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
func isLowerHexSHA256(value string) bool {
|
|
477
|
+
if len(value) != 64 {
|
|
478
|
+
return false
|
|
479
|
+
}
|
|
480
|
+
for i := range value {
|
|
481
|
+
if (value[i] < '0' || value[i] > '9') && (value[i] < 'a' || value[i] > 'f') {
|
|
482
|
+
return false
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return true
|
|
486
|
+
}
|