@restforgejs/platform 4.1.1 → 4.3.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/SECURITY.md +83 -4
- package/bin/sdf-tools.exe +0 -0
- package/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/dashboard/create.js +4 -1
- package/generators/cli/endpoint/create.js +43 -4
- package/generators/cli/key/generate.js +2 -1
- package/generators/cli/key/revoke.js +2 -1
- package/generators/cli/payload/diff.js +3 -2
- package/generators/cli/payload/generate.js +3 -2
- package/generators/cli/payload/sync.js +3 -2
- package/generators/cli/payload/validate.js +3 -2
- package/generators/cli/processor/create.js +14 -3
- package/generators/cli/project/delete.js +2 -1
- package/generators/cli/query/validate.js +3 -2
- package/generators/cli/schema/apply.js +526 -0
- package/generators/cli/schema/describe.js +3 -2
- package/generators/cli/schema/diff.js +322 -0
- package/generators/cli/schema/generate-ddl.js +7 -10
- package/generators/cli/schema/init.js +95 -172
- package/generators/cli/schema/introspect.js +3 -2
- package/generators/cli/schema/list.js +3 -2
- package/generators/cli/schema/migrate.js +13 -18
- package/generators/cli/schema/models.js +8 -12
- package/generators/cli/schema/template.js +222 -0
- package/generators/cli/schema/validate.js +8 -12
- package/generators/cli-entry.js +17 -2
- package/generators/lib/dbschema-kit/apply-engine.js +582 -0
- package/generators/lib/dbschema-kit/diff-engine.js +703 -0
- package/generators/lib/dbschema-kit/diff-reporter.js +272 -0
- package/generators/lib/dbschema-kit/emitters/alter-table.js +275 -0
- package/generators/lib/migration/audit-table-runner.js +213 -215
- package/generators/lib/payload/endpoint-schema-validator.js +171 -0
- package/generators/lib/payload/payload-runner.js +137 -220
- package/generators/lib/payload/schema-diff.js +277 -0
- package/generators/lib/templates/dashboard-catalog.js +1 -437
- package/generators/lib/templates/db-connection-env.js +1 -212
- package/generators/lib/templates/dbschema-catalog.js +1 -489
- package/generators/lib/templates/field-validation-catalog.js +1 -531
- package/generators/lib/templates/mysql-template.js +1 -3863
- package/generators/lib/templates/oracle-template.js +1 -3915
- package/generators/lib/templates/postgres-template.js +1 -5838
- package/generators/lib/templates/query-declarative-catalog.js +1 -199
- package/generators/lib/templates/sqlite-template.js +1 -3440
- package/generators/lib/utils/audit-columns.js +181 -0
- package/generators/lib/utils/cli-output.js +17 -0
- package/generators/lib/utils/database-introspector.js +16 -13
- package/generators/lib/utils/env-manager.js +6 -0
- package/generators/lib/utils/path-validator.js +71 -0
- package/generators/lib/validators/payload-validator.js +1 -2
- package/integrity-manifest.json +28 -10
- package/package.json +11 -3
- package/scripts/verify-integrity.js +1 -1
- package/server.js +1 -1
- package/src/components/handlers/adjust_handler.js +1 -1
- package/src/components/handlers/audit_handler.js +1 -1
- package/src/components/handlers/delete_handler.js +1 -1
- package/src/components/handlers/export_handler.js +1 -1
- package/src/components/handlers/import_handler.js +1 -1
- package/src/components/handlers/insert_handler.js +1 -1
- package/src/components/handlers/update_handler.js +1 -1
- package/src/components/handlers/upload_handler.js +1 -1
- package/src/components/handlers/workflow_handler.js +1 -1
- package/src/components/integrations/webhook.js +1 -1
- package/src/consumers/baseConsumer.js +1 -1
- package/src/consumers/declarativeMapper.js +1 -1
- package/src/consumers/handlers/apiHandler.js +1 -1
- package/src/consumers/handlers/consoleHandler.js +1 -1
- package/src/consumers/handlers/databaseHandler.js +1 -1
- package/src/consumers/handlers/index.js +1 -1
- package/src/consumers/handlers/kafkaHandler.js +1 -1
- package/src/consumers/index.js +1 -1
- package/src/consumers/messageTransformer.js +1 -1
- package/src/consumers/validator.js +1 -1
- package/src/core/db/dialect/base-dialect.js +1 -1
- package/src/core/db/dialect/index.js +1 -1
- package/src/core/db/dialect/mysql-dialect.js +1 -1
- package/src/core/db/dialect/oracle-dialect.js +1 -1
- package/src/core/db/dialect/postgres-dialect.js +1 -1
- package/src/core/db/dialect/sqlite-dialect.js +1 -1
- package/src/core/db/flatten-helper.js +1 -1
- package/src/core/db/query-builder-error.js +1 -1
- package/src/core/db/query-builder.js +1 -1
- package/src/core/db/relation-helper.js +1 -1
- package/src/core/handlers/delete_handler.js +1 -1
- package/src/core/handlers/insert_handler.js +1 -1
- package/src/core/handlers/update_handler.js +1 -1
- package/src/core/models/base-model.js +1 -1
- package/src/core/utils/cache-manager.js +1 -1
- package/src/core/utils/component-engine.js +1 -1
- package/src/core/utils/context-builder.js +1 -1
- package/src/core/utils/datetime-formatter.js +1 -1
- package/src/core/utils/datetime-parser.js +1 -1
- package/src/core/utils/db.js +1 -1
- package/src/core/utils/logger.js +1 -1
- package/src/core/utils/payload-loader.js +1 -1
- package/src/core/utils/security-checks.js +1 -1
- package/src/middleware/body-options.js +1 -1
- package/src/middleware/cors.js +1 -1
- package/src/middleware/idempotency.js +1 -1
- package/src/middleware/rate-limiter.js +1 -1
- package/src/middleware/request-logger.js +1 -1
- package/src/middleware/security-headers.js +1 -1
- package/src/models/base-model-mysql.js +1 -1
- package/src/models/base-model-oracle.js +1 -1
- package/src/models/base-model-sqlite.js +1 -1
- package/src/models/base-model.js +1 -1
- package/src/pro/caching/redis-client.js +1 -1
- package/src/pro/caching/redis-helper.js +1 -1
- package/src/pro/consumers/baseConsumer.js +1 -1
- package/src/pro/consumers/declarativeMapper.js +1 -1
- package/src/pro/consumers/handlers/apiHandler.js +1 -1
- package/src/pro/consumers/handlers/consoleHandler.js +1 -1
- package/src/pro/consumers/handlers/databaseHandler.js +1 -1
- package/src/pro/consumers/handlers/index.js +1 -1
- package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
- package/src/pro/consumers/index.js +1 -1
- package/src/pro/consumers/messageTransformer.js +1 -1
- package/src/pro/consumers/validator.js +1 -1
- package/src/pro/database/base-model-mysql.js +1 -1
- package/src/pro/database/base-model-oracle.js +1 -1
- package/src/pro/database/base-model-sqlite.js +1 -1
- package/src/pro/database/db-mysql.js +1 -1
- package/src/pro/database/db-oracle.js +1 -1
- package/src/pro/database/db-sqlite.js +1 -1
- package/src/pro/excel/excel-generator.js +1 -1
- package/src/pro/excel/excel-parser.js +1 -1
- package/src/pro/excel/export-service.js +1 -1
- package/src/pro/excel/export_handler.js +1 -1
- package/src/pro/excel/import-service.js +1 -1
- package/src/pro/excel/import-validator.js +1 -1
- package/src/pro/excel/import_handler.js +1 -1
- package/src/pro/excel/upsert-builder.js +1 -1
- package/src/pro/idgen/idgen-routes.js +1 -1
- package/src/pro/integrations/lookup-resolver.js +1 -1
- package/src/pro/integrations/upload-handler-v2.js +1 -1
- package/src/pro/integrations/upload-handler.js +1 -1
- package/src/pro/integrations/webhook.js +1 -1
- package/src/pro/locking/lock-routes.js +1 -1
- package/src/pro/locking/resource-lock-manager.js +1 -1
- package/src/pro/messaging/kafkaConsumerService.js +1 -1
- package/src/pro/messaging/kafkaService.js +1 -1
- package/src/pro/messaging/messagehubService.js +1 -1
- package/src/pro/messaging/rabbitmqService.js +1 -1
- package/src/pro/scheduler/job-manager.js +1 -1
- package/src/pro/scheduler/job-routes.js +1 -1
- package/src/pro/scheduler/job-validator.js +1 -1
- package/src/pro/storage/base-storage-provider.js +1 -1
- package/src/pro/storage/file-metadata-helper.js +1 -1
- package/src/pro/storage/index.js +1 -1
- package/src/pro/storage/local-storage-provider.js +1 -1
- package/src/pro/storage/s3-storage-provider.js +1 -1
- package/src/pro/storage/upload-cleanup-job.js +1 -1
- package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
- package/src/pro/storage/upload-pending-tracker.js +1 -1
- package/src/pro/websocket/broadcast-helper.js +1 -1
- package/src/pro/websocket/index.js +1 -1
- package/src/pro/websocket/livesync-server.js +1 -1
- package/src/pro/websocket/ws-broadcaster.js +1 -1
- package/src/services/export-service.js +1 -1
- package/src/services/import-service.js +1 -1
- package/src/services/kafkaConsumerService.js +1 -1
- package/src/services/kafkaService.js +1 -1
- package/src/services/messagehubService.js +1 -1
- package/src/services/rabbitmqService.js +1 -1
- package/src/utils/cache-invalidation-registry.js +1 -1
- package/src/utils/cache-manager.js +1 -1
- package/src/utils/component-engine.js +1 -1
- package/src/utils/config-extractor.js +1 -1
- package/src/utils/consumerLogger.js +1 -1
- package/src/utils/context-builder.js +1 -1
- package/src/utils/dashboard-helpers.js +1 -1
- package/src/utils/dateHelper.js +1 -1
- package/src/utils/datetime-formatter.js +1 -1
- package/src/utils/datetime-parser.js +1 -1
- package/src/utils/db-bootstrap.js +1 -1
- package/src/utils/db-mysql.js +1 -1
- package/src/utils/db-oracle.js +1 -1
- package/src/utils/db-sqlite.js +1 -1
- package/src/utils/db.js +1 -1
- package/src/utils/demo-generator.js +1 -1
- package/src/utils/excel-generator.js +1 -1
- package/src/utils/excel-parser.js +1 -1
- package/src/utils/file-watcher.js +1 -1
- package/src/utils/id-generator.js +1 -1
- package/src/utils/idempotency-manager.js +1 -1
- package/src/utils/import-validator.js +1 -1
- package/src/utils/license-client.js +1 -1
- package/src/utils/lock-manager.js +1 -1
- package/src/utils/logger.js +1 -1
- package/src/utils/lookup-resolver.js +1 -1
- package/src/utils/payload-loader.js +1 -1
- package/src/utils/processor-response.js +1 -1
- package/src/utils/rabbitmq.js +1 -1
- package/src/utils/redis-client.js +1 -1
- package/src/utils/redis-helper.js +1 -1
- package/src/utils/request-scope.js +1 -1
- package/src/utils/security-checks.js +1 -1
- package/src/utils/service-resolver.js +1 -1
- package/src/utils/shutdown-coordinator.js +1 -1
- package/src/utils/trusted-keys.js +1 -1
- package/src/utils/upload-handler.js +1 -1
- package/src/utils/upsert-builder.js +1 -1
- package/src/utils/workflow-hook-executor.js +1 -1
- package/generators/metadata/global.json +0 -58
- package/generators/metadata/test-mysql-workbench.json +0 -118
- package/generators/metadata/test-mysql.json +0 -56
- package/generators/metadata/test-oracle-workbench.json +0 -118
- package/generators/metadata/test-oracle.json +0 -56
- package/generators/metadata/test-pg-workbench.json +0 -118
- package/generators/metadata/test-pg.json +0 -56
- package/generators/scripts/obfuscate-source.js +0 -356
- package/generators/scripts/validate-catalog.js +0 -430
- package/generators/scripts/validate-dbschema-catalog.js +0 -708
- package/generators/tests/baseline/mysql/mini_inventory_item/src/models/mini-inventory/item.js +0 -944
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/oracle/mini_inventory_item/src/models/mini-inventory/item.js +0 -1002
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/postgres/mini_inventory_item/src/models/mini-inventory/item.js +0 -1333
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory/item.js +0 -1173
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory.js +0 -496
- package/generators/tests/fixtures/payloads/custom-sensitive.json +0 -27
- package/generators/tests/fixtures/payloads/dynamic-search-optout.json +0 -23
- package/generators/tests/fixtures/payloads/login-with-password.json +0 -22
- package/generators/tests/fixtures/payloads/order-process.json +0 -52
- package/generators/tests/fixtures/payloads/with-inline-sql.json +0 -26
- package/generators/tests/integration-tahap4b/README.md +0 -145
- package/generators/tests/integration-tahap4b/run-concurrent.js +0 -77
- package/generators/tests/integration-tahap4b/seed.sql +0 -53
- package/generators/tests/integration-tahap4b/verify.sql +0 -110
- package/generators/tests/unit/cli/create-dashboard.test.js +0 -505
- package/generators/tests/unit/cli/create-processor.test.js +0 -319
- package/generators/tests/unit/cli/dispatch-dashboard.test.js +0 -149
- package/generators/tests/unit/lib/dashboard-generator.test.js +0 -895
- package/generators/tests/unit/lib/dashboard-validator.test.js +0 -354
- package/generators/tests/unit/lib/dbschema-kit/apply-executor.test.js +0 -437
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-introspect.test.js +0 -393
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-generate-ddl.test.js +0 -104
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-init.test.js +0 -119
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-list.test.js +0 -48
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-migrate.test.js +0 -175
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-validate.test.js +0 -102
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-models.test.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/all-schemas-listing.js +0 -84
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/connection-error.js +0 -13
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/empty.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/multi-schema.js +0 -124
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/single-schema-inventory.js +0 -64
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/two-tables.js +0 -66
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/connection-error.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/partial.js +0 -29
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/rollback.js +0 -26
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/success.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/users.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/connection.test.js +0 -112
- package/generators/tests/unit/lib/dbschema-kit/ddl-generator.test.js +0 -205
- package/generators/tests/unit/lib/dbschema-kit/define-model.test.js +0 -56
- package/generators/tests/unit/lib/dbschema-kit/dialect/index.test.js +0 -46
- package/generators/tests/unit/lib/dbschema-kit/dialect/mysql.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/oracle.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/postgres.test.js +0 -131
- package/generators/tests/unit/lib/dbschema-kit/dialect/sqlite.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/driver-loader.test.js +0 -93
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-index.test.js +0 -173
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-table.test.js +0 -376
- package/generators/tests/unit/lib/dbschema-kit/emitters/drop-table.test.js +0 -78
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/invalid-dialect.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-dialect.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-host.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/oracle-valid.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/postgres-valid.env +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/sqlite-valid.env +0 -2
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-invalid/orphan.js +0 -17
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/public/users.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/extra/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/bar.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/foo.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/empty-folder/README.md +0 -1
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-export/plain.js +0 -3
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-schema/bad.js +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/legacy-pattern/legacy.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/audit/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/a/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/b/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/nested-deep/a/b/c/deep_table.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/.hidden/ignored.js +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/supplier.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound_item.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/item_product.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-single/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/integration.test.js +0 -217
- package/generators/tests/unit/lib/dbschema-kit/introspect-mapper.test.js +0 -403
- package/generators/tests/unit/lib/dbschema-kit/ir-builder.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/loader.test.js +0 -128
- package/generators/tests/unit/lib/dbschema-kit/naming.test.js +0 -170
- package/generators/tests/unit/lib/dbschema-kit/parser/shorthand-parser.test.js +0 -237
- package/generators/tests/unit/lib/dbschema-kit/schema-printer.test.js +0 -251
- package/generators/tests/unit/lib/dbschema-kit/statement-modifier.test.js +0 -105
- package/generators/tests/unit/lib/dbschema-kit/statement-splitter.test.js +0 -165
- package/generators/tests/unit/lib/dbschema-kit/topological-sort.test.js +0 -135
- package/generators/tests/unit/lib/dbschema-kit/validator/check-compatibility-validator.test.js +0 -373
- package/generators/tests/unit/lib/dbschema-kit/validator/circular-relation-validator.test.js +0 -454
- package/generators/tests/unit/lib/dbschema-kit/validator/cross-model-validator.test.js +0 -512
- package/generators/tests/unit/lib/dbschema-kit/validator/enhanced-validate-integration.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/validator/naming-convention-validator.test.js +0 -306
- package/generators/tests/unit/lib/dbschema-kit/validator/schema-validator.test.js +0 -443
- package/generators/tests/unit/lib/dbschema-kit/validator/type-compatibility-validator.test.js +0 -440
- package/generators/tests/unit/lib/dbschema-kit/validator/validator-reporter.test.js +0 -172
- package/generators/tests/unit/lib/metadata-manager-dashboard.test.js +0 -256
- package/generators/tests/unit/lib/payload-validator-fieldpolicy.test.js +0 -240
- package/generators/tests/unit/lib/processor-validation-generator.test.js +0 -300
- package/generators/tests/unit/lib/sensitive-field-masker.test.js +0 -170
- package/generators/tests/unit/lib/sql-table-extractor.test.js +0 -119
- package/scripts/generate-integrity-manifest.js +0 -124
- package/scripts/snapshot-cli-contracts.js +0 -194
- package/scripts/verify-publish.js +0 -56
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
const test = require('node:test');
|
|
2
|
-
const assert = require('node:assert');
|
|
3
|
-
|
|
4
|
-
const {
|
|
5
|
-
generateRouterValidationCode,
|
|
6
|
-
escapeSingleQuoted
|
|
7
|
-
} = require('../../../lib/generators/processor-validation-generator');
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Bangun stub router scope dan eksekusi blok validasi yang di-generate.
|
|
11
|
-
* Generated code dibungkus di inner function sehingga early return pada
|
|
12
|
-
* blok validasi (res.status(400).json(...)) tidak menghentikan flow
|
|
13
|
-
* pembacaan state dari resObj.
|
|
14
|
-
*/
|
|
15
|
-
function runValidationBlock(validationCode, input) {
|
|
16
|
-
const resObj = {
|
|
17
|
-
__done: false,
|
|
18
|
-
__payload: null,
|
|
19
|
-
__status: 0,
|
|
20
|
-
status(code) {
|
|
21
|
-
this.__status = code;
|
|
22
|
-
return this;
|
|
23
|
-
},
|
|
24
|
-
json(body) {
|
|
25
|
-
this.__done = true;
|
|
26
|
-
this.__payload = body;
|
|
27
|
-
return this;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
const inner = new Function('input', 'res', validationCode);
|
|
31
|
-
inner(input, resObj);
|
|
32
|
-
return {
|
|
33
|
-
done: resObj.__done,
|
|
34
|
-
payload: resObj.__payload,
|
|
35
|
-
status: resObj.__status
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
test('escapeSingleQuoted: escape backslash dan single quote', () => {
|
|
40
|
-
assert.strictEqual(escapeSingleQuoted("O'Brien"), "O\\'Brien");
|
|
41
|
-
assert.strictEqual(escapeSingleQuoted('path\\to'), 'path\\\\to');
|
|
42
|
-
assert.strictEqual(escapeSingleQuoted(''), '');
|
|
43
|
-
assert.strictEqual(escapeSingleQuoted(42), '');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('proc tanpa request: emit komentar no-op saja', () => {
|
|
47
|
-
const code = generateRouterValidationCode({ name: 'proc1' });
|
|
48
|
-
assert.match(code, /Tidak ada validation rules di payload/);
|
|
49
|
-
assert.doesNotMatch(code, /__validationErrors/);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('proc dengan request.validate:false: emit komentar opt-out', () => {
|
|
53
|
-
const code = generateRouterValidationCode({
|
|
54
|
-
name: 'proc1',
|
|
55
|
-
request: {
|
|
56
|
-
validate: false,
|
|
57
|
-
body: { x: { type: 'string', required: true } }
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
assert.match(code, /di-opt-out/);
|
|
61
|
-
assert.doesNotMatch(code, /__validationErrors/);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('proc dengan request tanpa field yang validable: emit komentar', () => {
|
|
65
|
-
const code = generateRouterValidationCode({
|
|
66
|
-
name: 'proc1',
|
|
67
|
-
request: { body: { note: {} } }
|
|
68
|
-
});
|
|
69
|
-
assert.match(code, /Tidak ada field yang perlu divalidasi/);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('required field string: menolak absent dan tipe salah', () => {
|
|
73
|
-
const code = generateRouterValidationCode({
|
|
74
|
-
name: 'proc1',
|
|
75
|
-
request: {
|
|
76
|
-
body: {
|
|
77
|
-
order_id: { type: 'string', required: true }
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
// Kode harus valid dan berisi __validationErrors.
|
|
82
|
-
assert.match(code, /const __validationErrors = \[\];/);
|
|
83
|
-
|
|
84
|
-
// Kasus absen: error "wajib diisi".
|
|
85
|
-
const r1 = runValidationBlock(code, {});
|
|
86
|
-
assert.strictEqual(r1.status, 400);
|
|
87
|
-
assert.strictEqual(r1.payload.errors.length, 1);
|
|
88
|
-
assert.match(r1.payload.errors[0].message, /wajib diisi/);
|
|
89
|
-
|
|
90
|
-
// Kasus tipe salah: error "harus berupa string".
|
|
91
|
-
const r2 = runValidationBlock(code, { order_id: 123 });
|
|
92
|
-
assert.strictEqual(r2.status, 400);
|
|
93
|
-
assert.match(r2.payload.errors[0].message, /harus berupa string/);
|
|
94
|
-
|
|
95
|
-
// Kasus valid.
|
|
96
|
-
const r3 = runValidationBlock(code, { order_id: 'abc' });
|
|
97
|
-
assert.strictEqual(r3.done, false);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('required field uuid: validate format', () => {
|
|
101
|
-
const code = generateRouterValidationCode({
|
|
102
|
-
name: 'proc1',
|
|
103
|
-
request: {
|
|
104
|
-
body: {
|
|
105
|
-
order_id: { type: 'uuid', required: true }
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const invalid = runValidationBlock(code, { order_id: 'not-a-uuid' });
|
|
111
|
-
assert.strictEqual(invalid.status, 400);
|
|
112
|
-
assert.match(invalid.payload.errors[0].message, /UUID yang valid/);
|
|
113
|
-
|
|
114
|
-
const valid = runValidationBlock(code, {
|
|
115
|
-
order_id: '550e8400-e29b-41d4-a716-446655440000'
|
|
116
|
-
});
|
|
117
|
-
assert.strictEqual(valid.done, false);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test('required field number: menolak non-numeric', () => {
|
|
121
|
-
const code = generateRouterValidationCode({
|
|
122
|
-
name: 'proc1',
|
|
123
|
-
request: {
|
|
124
|
-
body: { quantity: { type: 'number', required: true } }
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
const invalid = runValidationBlock(code, { quantity: 'abc' });
|
|
128
|
-
assert.strictEqual(invalid.status, 400);
|
|
129
|
-
assert.match(invalid.payload.errors[0].message, /harus berupa angka/);
|
|
130
|
-
|
|
131
|
-
const valid = runValidationBlock(code, { quantity: 42 });
|
|
132
|
-
assert.strictEqual(valid.done, false);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test('required field integer: menolak desimal', () => {
|
|
136
|
-
const code = generateRouterValidationCode({
|
|
137
|
-
name: 'proc1',
|
|
138
|
-
request: {
|
|
139
|
-
body: { qty: { type: 'integer', required: true } }
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
const invalid = runValidationBlock(code, { qty: 1.5 });
|
|
143
|
-
assert.strictEqual(invalid.status, 400);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('required field boolean: terima true/false/string', () => {
|
|
147
|
-
const code = generateRouterValidationCode({
|
|
148
|
-
name: 'proc1',
|
|
149
|
-
request: {
|
|
150
|
-
body: { is_active: { type: 'boolean', required: true } }
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
assert.strictEqual(runValidationBlock(code, { is_active: true }).done, false);
|
|
154
|
-
assert.strictEqual(runValidationBlock(code, { is_active: false }).done, false);
|
|
155
|
-
assert.strictEqual(runValidationBlock(code, { is_active: 'true' }).done, false);
|
|
156
|
-
assert.strictEqual(runValidationBlock(code, { is_active: 'maybe' }).status, 400);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
test('required field array: tolak non-array', () => {
|
|
160
|
-
const code = generateRouterValidationCode({
|
|
161
|
-
name: 'proc1',
|
|
162
|
-
request: {
|
|
163
|
-
body: { items: { type: 'array', required: true } }
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
const invalid = runValidationBlock(code, { items: 'not-array' });
|
|
167
|
-
assert.strictEqual(invalid.status, 400);
|
|
168
|
-
const valid = runValidationBlock(code, { items: [1, 2] });
|
|
169
|
-
assert.strictEqual(valid.done, false);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test('required field object: tolak array dan primitive', () => {
|
|
173
|
-
const code = generateRouterValidationCode({
|
|
174
|
-
name: 'proc1',
|
|
175
|
-
request: {
|
|
176
|
-
body: { payload: { type: 'object', required: true } }
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
assert.strictEqual(runValidationBlock(code, { payload: [] }).status, 400);
|
|
180
|
-
assert.strictEqual(runValidationBlock(code, { payload: 'x' }).status, 400);
|
|
181
|
-
assert.strictEqual(runValidationBlock(code, { payload: { a: 1 } }).done, false);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test('enum whitelist: tolak nilai di luar daftar', () => {
|
|
185
|
-
const code = generateRouterValidationCode({
|
|
186
|
-
name: 'proc1',
|
|
187
|
-
request: {
|
|
188
|
-
body: {
|
|
189
|
-
status: { type: 'string', required: true, enum: ['draft', 'approved', 'rejected'] }
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
const invalid = runValidationBlock(code, { status: 'hacked' });
|
|
194
|
-
assert.strictEqual(invalid.status, 400);
|
|
195
|
-
assert.match(invalid.payload.errors[0].message, /tidak termasuk nilai yang diizinkan/);
|
|
196
|
-
|
|
197
|
-
const valid = runValidationBlock(code, { status: 'approved' });
|
|
198
|
-
assert.strictEqual(valid.done, false);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test('minLength/maxLength untuk string', () => {
|
|
202
|
-
const code = generateRouterValidationCode({
|
|
203
|
-
name: 'proc1',
|
|
204
|
-
request: {
|
|
205
|
-
body: {
|
|
206
|
-
note: { type: 'string', required: true, minLength: 3, maxLength: 10 }
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
assert.strictEqual(runValidationBlock(code, { note: 'ab' }).status, 400);
|
|
211
|
-
assert.strictEqual(runValidationBlock(code, { note: 'hello world!' }).status, 400);
|
|
212
|
-
assert.strictEqual(runValidationBlock(code, { note: 'hello' }).done, false);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
test('format email: validate regex email', () => {
|
|
216
|
-
const code = generateRouterValidationCode({
|
|
217
|
-
name: 'proc1',
|
|
218
|
-
request: {
|
|
219
|
-
body: {
|
|
220
|
-
email: { type: 'string', required: true, format: 'email' }
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
assert.strictEqual(runValidationBlock(code, { email: 'not-email' }).status, 400);
|
|
225
|
-
assert.strictEqual(runValidationBlock(code, { email: 'a@b.co' }).done, false);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test('header mapTo: generate validasi pada nama mapTo, bukan nama header', () => {
|
|
229
|
-
const code = generateRouterValidationCode({
|
|
230
|
-
name: 'proc1',
|
|
231
|
-
request: {
|
|
232
|
-
headers: {
|
|
233
|
-
'X-App-Code': { type: 'string', required: true, mapTo: 'app_code' }
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
assert.doesNotMatch(code, /input\['X-App-Code'\]/);
|
|
239
|
-
assert.match(code, /input\['app_code'\]/);
|
|
240
|
-
assert.match(code, /Header X-App-Code/);
|
|
241
|
-
|
|
242
|
-
const missing = runValidationBlock(code, {});
|
|
243
|
-
assert.strictEqual(missing.status, 400);
|
|
244
|
-
const ok = runValidationBlock(code, { app_code: 'sales' });
|
|
245
|
-
assert.strictEqual(ok.done, false);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test('non-required field: skip jika absen, tapi validate jika value ada', () => {
|
|
249
|
-
const code = generateRouterValidationCode({
|
|
250
|
-
name: 'proc1',
|
|
251
|
-
request: {
|
|
252
|
-
body: {
|
|
253
|
-
tag: { type: 'string', minLength: 2 }
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// absent -> tidak ada error.
|
|
259
|
-
assert.strictEqual(runValidationBlock(code, {}).done, false);
|
|
260
|
-
// present tapi tidak lolos minLength.
|
|
261
|
-
assert.strictEqual(runValidationBlock(code, { tag: 'x' }).status, 400);
|
|
262
|
-
// present dan lolos.
|
|
263
|
-
assert.strictEqual(runValidationBlock(code, { tag: 'ok' }).done, false);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
test('kode yang di-generate tidak expose field name user sebagai kode eksekusi', () => {
|
|
267
|
-
// Nama field dengan single quote dan backslash di-escape.
|
|
268
|
-
const code = generateRouterValidationCode({
|
|
269
|
-
name: 'proc1',
|
|
270
|
-
request: {
|
|
271
|
-
body: {
|
|
272
|
-
"foo'; return 42; //": { type: 'string', required: true }
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
// Kode masih bisa di-compile.
|
|
277
|
-
const fn = new Function('input', 'res', `${code}\nreturn true;`);
|
|
278
|
-
const res = { status: () => ({ json: () => {} }) };
|
|
279
|
-
assert.doesNotThrow(() => fn({}, res));
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
test('multiple field dari body dan headers: semua error terkumpul (fail fast per field)', () => {
|
|
283
|
-
const code = generateRouterValidationCode({
|
|
284
|
-
name: 'proc1',
|
|
285
|
-
request: {
|
|
286
|
-
body: {
|
|
287
|
-
order_id: { type: 'uuid', required: true },
|
|
288
|
-
qty: { type: 'integer', required: true }
|
|
289
|
-
},
|
|
290
|
-
headers: {
|
|
291
|
-
'X-App-Code': { type: 'string', required: true, mapTo: 'app_code' }
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
const result = runValidationBlock(code, {});
|
|
296
|
-
assert.strictEqual(result.status, 400);
|
|
297
|
-
assert.strictEqual(result.payload.errors.length, 3);
|
|
298
|
-
const fields = result.payload.errors.map(e => e.field).sort();
|
|
299
|
-
assert.deepStrictEqual(fields, ['app_code', 'order_id', 'qty']);
|
|
300
|
-
});
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
const test = require('node:test');
|
|
2
|
-
const assert = require('node:assert');
|
|
3
|
-
|
|
4
|
-
const masker = require('../../../lib/utils/sensitive-field-masker');
|
|
5
|
-
|
|
6
|
-
test('maskSensitive: mask field dengan nama password', () => {
|
|
7
|
-
const input = { username: 'ibrahim', password: 'secret123' };
|
|
8
|
-
const out = masker.maskSensitive(input);
|
|
9
|
-
assert.strictEqual(out.password, '***MASKED***');
|
|
10
|
-
assert.strictEqual(out.username, 'ibrahim');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('maskSensitive: mask berbagai nama field sensitif yang umum', () => {
|
|
14
|
-
const input = {
|
|
15
|
-
token: 'abc',
|
|
16
|
-
apiKey: 'xyz',
|
|
17
|
-
api_key: 'xyz',
|
|
18
|
-
credit_card: '4111-1111',
|
|
19
|
-
cardNumber: '4111-1111',
|
|
20
|
-
cvv: '123',
|
|
21
|
-
ssn: '000-00-0000',
|
|
22
|
-
pin: '1234',
|
|
23
|
-
privateKey: 'RSA',
|
|
24
|
-
refresh_token: 'r',
|
|
25
|
-
accessToken: 'a',
|
|
26
|
-
otp: '999999',
|
|
27
|
-
mfa: 'Y',
|
|
28
|
-
authorization: 'Bearer x',
|
|
29
|
-
auth: 'Bearer x'
|
|
30
|
-
};
|
|
31
|
-
const out = masker.maskSensitive(input);
|
|
32
|
-
for (const key of Object.keys(input)) {
|
|
33
|
-
assert.strictEqual(out[key], '***MASKED***', `Field ${key} seharusnya ter-mask`);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('maskSensitive: case insensitive (PASSWORD, Password, password)', () => {
|
|
38
|
-
const out = masker.maskSensitive({
|
|
39
|
-
PASSWORD: 'x',
|
|
40
|
-
Password: 'y',
|
|
41
|
-
password: 'z'
|
|
42
|
-
});
|
|
43
|
-
assert.strictEqual(out.PASSWORD, '***MASKED***');
|
|
44
|
-
assert.strictEqual(out.Password, '***MASKED***');
|
|
45
|
-
assert.strictEqual(out.password, '***MASKED***');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('maskSensitive: rekursif pada nested object', () => {
|
|
49
|
-
const out = masker.maskSensitive({
|
|
50
|
-
user: { name: 'a', password: 'b', nested: { token: 't' } },
|
|
51
|
-
items: [{ secret: 'x' }, { ok: 'v' }]
|
|
52
|
-
});
|
|
53
|
-
assert.strictEqual(out.user.password, '***MASKED***');
|
|
54
|
-
assert.strictEqual(out.user.name, 'a');
|
|
55
|
-
assert.strictEqual(out.user.nested.token, '***MASKED***');
|
|
56
|
-
assert.strictEqual(out.items[0].secret, '***MASKED***');
|
|
57
|
-
assert.strictEqual(out.items[1].ok, 'v');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('maskSensitive: return nilai primitive apa adanya', () => {
|
|
61
|
-
assert.strictEqual(masker.maskSensitive(null), null);
|
|
62
|
-
assert.strictEqual(masker.maskSensitive(undefined), undefined);
|
|
63
|
-
assert.strictEqual(masker.maskSensitive(42), 42);
|
|
64
|
-
assert.strictEqual(masker.maskSensitive('plain string'), 'plain string');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('maskSensitive: tidak melakukan mutasi pada object asli', () => {
|
|
68
|
-
const original = { password: 'orig', name: 'ibrahim' };
|
|
69
|
-
const out = masker.maskSensitive(original);
|
|
70
|
-
assert.strictEqual(original.password, 'orig');
|
|
71
|
-
assert.notStrictEqual(out, original);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('maskSensitive: field name yang mengandung substring sensitif tidak di-mask', () => {
|
|
75
|
-
const out = masker.maskSensitive({
|
|
76
|
-
password_hint: 'nama hewan peliharaan',
|
|
77
|
-
my_token_description: 'deskripsi',
|
|
78
|
-
secretly_happy: 'v'
|
|
79
|
-
});
|
|
80
|
-
assert.strictEqual(out.password_hint, 'nama hewan peliharaan');
|
|
81
|
-
assert.strictEqual(out.my_token_description, 'deskripsi');
|
|
82
|
-
assert.strictEqual(out.secretly_happy, 'v');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('isFieldSensitive: flag explicit sensitive:true mengalahkan pattern', () => {
|
|
86
|
-
assert.strictEqual(masker.isFieldSensitive('nickname', { sensitive: true }), true);
|
|
87
|
-
assert.strictEqual(masker.isFieldSensitive('password', {}), true);
|
|
88
|
-
assert.strictEqual(masker.isFieldSensitive('email', {}), false);
|
|
89
|
-
assert.strictEqual(masker.isFieldSensitive('email', null), false);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('sanitizeExtraKeywords: filter karakter tidak aman dan duplikat', () => {
|
|
93
|
-
const out = masker.sanitizeExtraKeywords([
|
|
94
|
-
'ktp_number',
|
|
95
|
-
'npwp',
|
|
96
|
-
'123bad', // tidak boleh: mulai angka
|
|
97
|
-
'has space', // tidak boleh: mengandung spasi
|
|
98
|
-
'regex.*inject', // tidak boleh: meta character
|
|
99
|
-
'alpha|beta', // tidak boleh: pipe injection
|
|
100
|
-
'NPWP', // duplikat lowercase dari npwp
|
|
101
|
-
42, // tidak boleh: bukan string
|
|
102
|
-
null
|
|
103
|
-
]);
|
|
104
|
-
assert.deepStrictEqual(out, ['ktp_number', 'npwp']);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test('buildMaskerHelperCode: output adalah kode JS valid dan fungsional', () => {
|
|
108
|
-
const code = masker.buildMaskerHelperCode({ extraKeywords: ['ktp_number'] });
|
|
109
|
-
// Compile dan jalankan kode untuk verify fungsional.
|
|
110
|
-
const runner = new Function(`${code}\nreturn __maskSensitive(arguments[0]);`);
|
|
111
|
-
const result = runner({
|
|
112
|
-
password: 'x',
|
|
113
|
-
ktp_number: '3201234',
|
|
114
|
-
name: 'ibrahim',
|
|
115
|
-
nested: { token: 't' }
|
|
116
|
-
});
|
|
117
|
-
assert.strictEqual(result.password, '***MASKED***');
|
|
118
|
-
assert.strictEqual(result.ktp_number, '***MASKED***');
|
|
119
|
-
assert.strictEqual(result.name, 'ibrahim');
|
|
120
|
-
assert.strictEqual(result.nested.token, '***MASKED***');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('buildMaskerHelperCode: reject regex injection via extra keyword', () => {
|
|
124
|
-
// Keyword berbahaya di-filter sebelum di-embed ke regex.
|
|
125
|
-
const code = masker.buildMaskerHelperCode({ extraKeywords: ['.*', '|password|'] });
|
|
126
|
-
const runner = new Function(`${code}\nreturn __maskSensitive(arguments[0]);`);
|
|
127
|
-
const result = runner({ normal_field: 'ok', password: 'x' });
|
|
128
|
-
// normal_field tidak boleh ter-mask (tidak ada regex '.*' yang aktif).
|
|
129
|
-
assert.strictEqual(result.normal_field, 'ok');
|
|
130
|
-
// Default pattern tetap bekerja untuk password.
|
|
131
|
-
assert.strictEqual(result.password, '***MASKED***');
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test('buildMaskerHelperCode: output dengan extraKeywords kosong tidak mengandung pipe trailing', () => {
|
|
135
|
-
const code = masker.buildMaskerHelperCode();
|
|
136
|
-
assert.ok(!/mfa\|\)/.test(code), 'Regex tidak boleh memiliki pipe tanpa alternative');
|
|
137
|
-
assert.ok(/mfa\)/.test(code), 'Regex harus diakhiri dengan mfa');
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test('collectExplicitSensitiveKeywords: collect unique field dari semua processor', () => {
|
|
141
|
-
const processors = [
|
|
142
|
-
{
|
|
143
|
-
request: {
|
|
144
|
-
body: {
|
|
145
|
-
ktp_number: { type: 'string', sensitive: true },
|
|
146
|
-
normal: { type: 'string' }
|
|
147
|
-
},
|
|
148
|
-
headers: {
|
|
149
|
-
'X-Token-ID': { type: 'string', mapTo: 'token_id', sensitive: true }
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
request: {
|
|
155
|
-
body: {
|
|
156
|
-
ktp_number: { type: 'string', sensitive: true },
|
|
157
|
-
npwp: { type: 'string', sensitive: true }
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
];
|
|
162
|
-
const out = masker.collectExplicitSensitiveKeywords(processors);
|
|
163
|
-
assert.deepStrictEqual(out.sort(), ['ktp_number', 'npwp', 'token_id']);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test('collectExplicitSensitiveKeywords: handle payload kosong atau tanpa request', () => {
|
|
167
|
-
assert.deepStrictEqual(masker.collectExplicitSensitiveKeywords([]), []);
|
|
168
|
-
assert.deepStrictEqual(masker.collectExplicitSensitiveKeywords(null), []);
|
|
169
|
-
assert.deepStrictEqual(masker.collectExplicitSensitiveKeywords([{ name: 'x' }]), []);
|
|
170
|
-
});
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const test = require('node:test');
|
|
4
|
-
const assert = require('node:assert');
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
extractTables,
|
|
8
|
-
extractTablesUnion,
|
|
9
|
-
_stripCommentsAndStrings
|
|
10
|
-
} = require('../../../lib/utils/sql-table-extractor');
|
|
11
|
-
|
|
12
|
-
function setEquals(a, b) {
|
|
13
|
-
if (a.size !== b.size) return false;
|
|
14
|
-
for (const v of a) if (!b.has(v)) return false;
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
test('extractTables: empty string returns empty set', () => {
|
|
19
|
-
const result = extractTables('');
|
|
20
|
-
assert.strictEqual(result.size, 0);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('extractTables: simple FROM clause captures table name', () => {
|
|
24
|
-
const result = extractTables('SELECT * FROM users');
|
|
25
|
-
assert.ok(setEquals(result, new Set(['users'])));
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('extractTables: FROM + JOIN captured, names lowercased', () => {
|
|
29
|
-
const result = extractTables('SELECT * FROM Users JOIN Orders ON Users.id = Orders.user_id');
|
|
30
|
-
assert.ok(setEquals(result, new Set(['users', 'orders'])));
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('extractTables: schema prefix stripped (public.users -> users)', () => {
|
|
34
|
-
const result = extractTables('SELECT * FROM public.users');
|
|
35
|
-
assert.ok(setEquals(result, new Set(['users'])));
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('extractTables: multi-line SQL with INNER/LEFT JOIN — semua tertangkap', () => {
|
|
39
|
-
const sql = `
|
|
40
|
-
SELECT a.*, b.name, c.total
|
|
41
|
-
FROM stock_inbound a
|
|
42
|
-
INNER JOIN supplier b ON b.id = a.supplier_id
|
|
43
|
-
LEFT JOIN product c ON c.id = a.product_id
|
|
44
|
-
WHERE a.year = :year
|
|
45
|
-
`;
|
|
46
|
-
const result = extractTables(sql);
|
|
47
|
-
assert.ok(setEquals(result, new Set(['stock_inbound', 'supplier', 'product'])));
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('extractTables: WITH CTE — cte name tertangkap (caller filter via metadata)', () => {
|
|
51
|
-
const sql = 'WITH cte AS (SELECT 1 AS x) SELECT * FROM cte';
|
|
52
|
-
const result = extractTables(sql);
|
|
53
|
-
assert.ok(result.has('cte'));
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('extractTables: single-line comment "-- FROM tablefake" tidak match', () => {
|
|
57
|
-
const sql = 'SELECT * FROM users -- FROM tablefake\nWHERE id = 1';
|
|
58
|
-
const result = extractTables(sql);
|
|
59
|
-
assert.ok(setEquals(result, new Set(['users'])));
|
|
60
|
-
assert.ok(!result.has('tablefake'));
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('extractTables: literal string "FROM tablefake" tidak match', () => {
|
|
64
|
-
const sql = "SELECT 'FROM tablefake' AS label FROM users";
|
|
65
|
-
const result = extractTables(sql);
|
|
66
|
-
assert.ok(setEquals(result, new Set(['users'])));
|
|
67
|
-
assert.ok(!result.has('tablefake'));
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('extractTables: multi-line comment /* FROM x */ tidak match', () => {
|
|
71
|
-
const sql = 'SELECT * /* FROM tablefake */ FROM users';
|
|
72
|
-
const result = extractTables(sql);
|
|
73
|
-
assert.ok(setEquals(result, new Set(['users'])));
|
|
74
|
-
assert.ok(!result.has('tablefake'));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('extractTables: function-as-table FROM unnest(...) — unnest tertangkap (caller filter)', () => {
|
|
78
|
-
const sql = 'SELECT v FROM unnest(ARRAY[1,2,3]) AS v';
|
|
79
|
-
const result = extractTables(sql);
|
|
80
|
-
assert.ok(result.has('unnest'));
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('extractTablesUnion: union dari beberapa SQL string', () => {
|
|
84
|
-
const result = extractTablesUnion([
|
|
85
|
-
'SELECT * FROM a',
|
|
86
|
-
'SELECT * FROM b JOIN a ON a.id = b.a_id'
|
|
87
|
-
]);
|
|
88
|
-
assert.ok(setEquals(result, new Set(['a', 'b'])));
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('extractTables: real-world SQL dengan FROM + multiple JOIN', () => {
|
|
92
|
-
const sql = `
|
|
93
|
-
SELECT
|
|
94
|
-
si.id,
|
|
95
|
-
s.name AS supplier_name,
|
|
96
|
-
p.name AS product_name
|
|
97
|
-
FROM stock_inbound si
|
|
98
|
-
JOIN supplier s ON s.id = si.supplier_id
|
|
99
|
-
JOIN product p ON p.id = si.product_id
|
|
100
|
-
WHERE si.year = :year
|
|
101
|
-
`;
|
|
102
|
-
const result = extractTables(sql);
|
|
103
|
-
assert.ok(setEquals(result, new Set(['stock_inbound', 'supplier', 'product'])));
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('_stripCommentsAndStrings: line comment, block comment, dan literal string semua di-strip', () => {
|
|
107
|
-
const sql = "SELECT 'FROM x' /* FROM y */ FROM users -- FROM z";
|
|
108
|
-
const cleaned = _stripCommentsAndStrings(sql);
|
|
109
|
-
assert.ok(!/FROM x/.test(cleaned));
|
|
110
|
-
assert.ok(!/FROM y/.test(cleaned));
|
|
111
|
-
assert.ok(!/FROM z/.test(cleaned));
|
|
112
|
-
assert.ok(/FROM users/.test(cleaned));
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('extractTables: non-string input (null/undefined/number) returns empty set', () => {
|
|
116
|
-
assert.strictEqual(extractTables(null).size, 0);
|
|
117
|
-
assert.strictEqual(extractTables(undefined).size, 0);
|
|
118
|
-
assert.strictEqual(extractTables(42).size, 0);
|
|
119
|
-
});
|