-
Notifications
You must be signed in to change notification settings - Fork 14
feat(admin-scripts): add Admin Script Runner service #517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
feat(admin-scripts): add Admin Script Runner service #517
Conversation
Add comprehensive plan for Admin Script Runner service aligned with next branch architecture (command pattern, repository factories, Prisma schemas, multi-database support). Includes initial package structure for @friggframework/admin-scripts.
- Add AdminScriptBase.Definition following IntegrationBase pattern (ref: packages/core/integrations/integration-base.js:57-69) - Add appDefinition.adminScripts schema update (ref: packages/devtools/infrastructure/domains/shared/types/app-definition.js) - Make integrationFactory OPTIONAL for scripts that only need DB access - Add AdminFriggCommands with repository pattern matching existing commands - Include exact file references throughout plan
- ADR-5: Execution modes - sync (optional) vs async (default) - ADR-6: Hybrid scheduling (Definition defaults + DB/API overrides) - ADR-7: DDD/hexagonal architecture layers documented - ADR-8: SchedulerAdapter port with AWS/local implementations - ADR-9: AdminScriptBuilder following infrastructure-composer pattern - Add ScriptSchedule Prisma model for hybrid scheduling - Document deployment flow and generated serverless resources - Update package structure with adapters directory - Update Files to Create/Modify section with all new files
- ADR-10: Dry run via repository wrapper + HTTP interceptor - Intercepts DB writes, logs operations, returns unchanged data - Intercepts external API calls via mock axios instance - Script code unchanged between normal and dry-run modes - ADR-11: Self-queuing for long-running scripts - Scripts chunk work and re-queue via frigg.queueScript() - Tracks parentExecutionId for lineage - No Step Functions complexity - Remove VM sandbox (not needed for trusted adopter scripts) - Update package structure with dry-run files
- Replace raw SQS code with QueuerUtil.send() and batchSend() - Reference: packages/core/queues/queuer-util.js - Added queueScriptBatch() for bulk operations
Phase 1 implementation of Admin Script Runner service: Repository Layer: - AdminApiKey repositories (MongoDB, PostgreSQL, DocumentDB) - ScriptExecution repositories (MongoDB, PostgreSQL, DocumentDB) - Factory pattern for database-agnostic creation - 70 unit tests passing Application Layer: - createAdminScriptCommands() factory with: - API key management (create, validate, list, deactivate) - Execution lifecycle (create, update, complete) - bcrypt hashing for key security - Error mapping to HTTP status codes Infrastructure Layer: - AdminScriptBuilder wired into infrastructure-composer - Generates SQS queue, Lambda functions, EventBridge scheduler - 33 unit tests passing Prisma Schema: - AdminApiKey model with scopes and expiration - ScriptExecution model with status, logs, metrics
Application Layer: - AdminScriptBase: Base class for all admin scripts with Definition pattern - ScriptFactory: Registry for script registration and instantiation - AdminFriggCommands: Helper API for scripts (db access, queue, logging) - ScriptRunner: Orchestrates script execution with error handling Infrastructure Layer: - admin-auth-middleware: Bearer token authentication for admin API keys - admin-script-router: Express router with 5 endpoints for script management - script-executor-handler: SQS worker Lambda for async execution Features: - Sync and async execution modes - Self-queuing pattern via QueuerUtil for long-running scripts - Audit trail (API key, IP address) - Automatic log persistence to execution records Test Coverage: 110 tests passing
…h check Built-in Scripts: - OAuthTokenRefreshScript: Refreshes OAuth tokens near expiry - Configurable expiry threshold (default 24h) - Dry-run mode for safe testing - Filters by integration IDs or all - IntegrationHealthCheckScript: Checks integration health - Validates credential presence and expiry - Tests API connectivity - Optionally updates integration status - Schedule-ready (daily cron expression) Both scripts: - Extend AdminScriptBase with Definition pattern - Use AdminFriggCommands for database/API access - Include JSON Schema for input/output validation - Comprehensive error handling and logging Test Coverage: 41 tests passing for built-in scripts
Fixed a bug where the logs array from Prisma was being mutated directly instead of creating a copy first. This caused test failures when the original array reference was used for comparison.
Phase 2 - Hybrid Scheduling:
- ScriptSchedule Prisma model (MongoDB + PostgreSQL)
- ScriptSchedule repository implementations with factory
- SchedulerAdapter port interface (hexagonal pattern)
- AWSSchedulerAdapter for EventBridge Scheduler
- LocalSchedulerAdapter for dev/test
- Schedule management API endpoints:
- GET /scripts/:name/schedule (DB override > Definition default)
- PUT /scripts/:name/schedule (create/update override)
- DELETE /scripts/:name/schedule (revert to default)
- Schedule commands in admin-script-commands.js
Phase 3 - Dry-Run Mode:
- DryRunRepositoryWrapper: Proxy-based write interception
- DryRunHttpInterceptor: Mock HTTP client with service detection
- Automatic sanitization of sensitive data in logs
- Returns preview with operation log and summary
- POST /execute { dryRun: true } support
Features:
- 20+ external service detection (HubSpot, Salesforce, Slack, etc.)
- Smart read vs write operation detection
- Timezone-aware scheduling
- AWS EventBridge rule tracking (ruleArn, ruleName)
Test Coverage: 424 tests passing (141 new tests added)
- Remove commented-out domain model placeholders (not needed with repository pattern) - Remove commented-out factory function placeholder - Clarify EventBridge Scheduler integration comments as optional enhancement
- Integrate createSchedulerAdapter into PUT /schedule endpoint - Provision EventBridge rule when schedule is enabled with cron expression - Delete EventBridge rule when schedule is disabled or deleted - Store AWS rule ARN/name in database for tracking - Handle scheduler errors gracefully (non-fatal, with warning in response) - Add 6 new tests for scheduler integration
Align naming with AWS EventBridge Scheduler terminology: - awsRuleArn → awsScheduleArn - awsRuleName → awsScheduleName - updateScheduleAwsRule → updateScheduleAwsInfo - ruleArn → scheduleArn (adapter return values) - ruleName → scheduleName (adapter return values) This reflects that we use EventBridge Scheduler (the newer service), not EventBridge Rules (the older approach).
Document the design decisions for the Admin Script Runner: - Entry point via appDefinition.adminScripts - Script base class pattern following IntegrationBase - Infrastructure components (builder, repositories, handlers) - Execution modes (sync/async) - Hybrid scheduling with EventBridge Scheduler - Dry-run mode for safe testing - Security model with admin API keys Also update README to include ADR-004 and ADR-005.
The admin-script-router requires express and serverless-http but they were not declared in package.json, causing the release to fail.
The @unique constraint on keyHash already creates an index, so the explicit @@index([keyHash]) was causing a "Index already exists" error.
Replace global parseInt/isNaN with Number.parseInt/Number.isNaN to follow JavaScript best practices and pass SonarCloud analysis.
- Extract ScheduleManagementUseCase from admin-script-router - Encapsulates schedule business logic (get/upsert/delete) - Handles EventBridge sync with graceful error handling - 14 unit tests with full coverage - Refactor oauth-token-refresh.js - Extract _checkRefreshPrerequisites() for token validation - Extract _performTokenRefresh() for actual refresh logic - Extract _createResult() helper for consistent response format - Refactor integration-health-check.js - Extract _createCheckResult() for initial result structure - Extract _runChecks() to orchestrate all checks - Extract _addCheckResult() to track issues - Extract _determineOverallStatus() for status logic - Extract _handleCheckError() for error handling All 297 tests passing.
- Add id-token: write permission for OIDC authentication - Add contents: write permission for release commits - Upgrade npm to latest for trusted publishing support (requires 11.5.1+) - Remove NPM_TOKEN/NODE_AUTH_TOKEN (OIDC replaces token auth) Requires configuring trusted publishers on npmjs.com for each package.
Keep both OIDC permissions and NPM_TOKEN for flexibility: - Packages with trusted publisher configured → use OIDC - New packages (e.g., admin-scripts) → fall back to token This allows gradual migration to OIDC while supporting new package publishes.
packages/admin-scripts/package.json
Outdated
| "bcryptjs": "^2.4.3", | ||
| "express": "^4.18.2", | ||
| "lodash": "4.17.21", | ||
| "mongoose": "6.11.6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why mongoose?
| "jest": "^29.7.0", | ||
| "prettier": "^2.7.1", | ||
| "sinon": "^16.1.1", | ||
| "supertest": "^7.1.4" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already use nock for http request mocking.
packages/admin-scripts/package.json
Outdated
| "@friggframework/eslint-config": "^2.0.0-next.0", | ||
| "@friggframework/prettier-config": "^2.0.0-next.0", | ||
| "@friggframework/test": "^2.0.0-next.0", | ||
| "chai": "^4.3.6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chai and sinon should slowly be pushed away in favor or newer test libs like vitest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't understand why we can not use the user table from the database
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we call it just script-repository.js?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't the schedule information be included in the current script-execution (hopefully just script) table?
| console.log(`\n[${this.name}] Configuring admin scripts...`); | ||
| console.log(` Processing ${appDefinition.adminScripts.length} scripts...`); | ||
|
|
||
| const usePrismaLayer = appDefinition.usePrismaLambdaLayer !== false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is prisma layer important here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a composer class?
Phase 1 of admin refactoring based on Daniel's PR review: 1. Auth simplification (ENV-based like db-migrate): - Add shared validateAdminApiKey middleware in core/handlers/middleware - Delete AdminApiKey model, repositories, and tests - Remove API key commands from admin-script-commands.js 2. Schema changes: - Replace AdminApiKey + ScriptExecution with AdminProcess model - AdminProcess mirrors Process but without user/integration FK - Supports hierarchy (parentProcessId, childProcesses) - Used for: admin scripts, db migrations, system tasks 3. Files deleted: - admin-api-key-repository-*.js (all variants) - admin-api-key tests Next steps: Create AdminProcess repository, refactor routes to /admin/scripts/:name convention, unify db-migrate under /admin.
…r /admin Major refactoring based on PR feedback: 1. AdminProcess Repository (replaces ScriptExecution): - New: admin-process-repository-interface.js - New: admin-process-repository-mongo.js - New: admin-process-repository-postgres.js - New: admin-process-repository-documentdb.js - New: admin-process-repository-factory.js - Deleted: All script-execution-repository-* files 2. Updated admin-scripts package: - All files now use AdminProcess methods - Updated: admin-script-base.js, admin-frigg-commands.js, script-runner.js - Updated: admin-script-router.js, script-executor-handler.js - Fixed export: validateAdminApiKey (not adminAuthMiddleware) 3. Moved db-migrate under /admin path: - Routes: /admin/db-migrate/* - Uses shared validateAdminApiKey middleware - Updated use-cases and tests 4. Cleaned up obsolete code: - Removed AdminApiKey tests from admin-script-commands.test.js - Updated all tests for AdminProcess methods All 295 tests passing.
Address PR feedback from Daniel: 1. Simplified dry-run implementation: - Deleted over-engineered dry-run-repository-wrapper.js (262 lines) - Deleted over-engineered dry-run-http-interceptor.js (297 lines) - New dry-run validates inputs and returns preview without executing - Added JSON schema validation for script parameters - Net reduction: ~990 lines removed 2. Cleaned up package.json: - Removed unused mongoose dependency - Removed unused chai devDependency - Kept supertest for Express route testing (different from nock) 3. Documented admin-script-commands architecture: - Explained why separate from integration-commands - integration-commands: user-context operations (requires integrationClass) - admin-script-commands: system operations (no user context) - Separation follows SRP and avoids coupling Tests: 262 passing
…Runner Changes: - Rename requiresIntegrationFactory to requireIntegrationInstance (PR feedback) - Add JSDoc documentation for executionId parameter - Split schedule-management-use-case.js into 3 separate use cases following SRP: - GetEffectiveScheduleUseCase - UpsertScheduleUseCase - DeleteScheduleUseCase - Abstract AWS-specific naming to generic external scheduler terminology: - awsScheduleArn → externalScheduleId - awsScheduleName → externalScheduleName - updateScheduleAwsInfo → updateScheduleExternalInfo - Remove sinon dependency, use Jest mocks instead - Update Prisma schemas for both MongoDB and PostgreSQL - Update ADR documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ename context - Rename AdminFriggCommands → AdminScriptContext (facade pattern) - Refactor to constructor injection (context via constructor, not execute) - Remove logging from AdminScriptBase (use context.log instead) - Clean up display object - only UI-specific overrides - Strip verbose JSDoc comments (keep code sparse) - Update all tests for new API - Add PR review tracker for remaining items 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|




Summary
Adds Admin Script Runner service - enables Frigg adopters to write and execute scripts in hosted environments with VPC/KMS secured database access.
Phase 1: MVP
AdminApiKey,ScriptExecution(MongoDB + PostgreSQL)createAdminScriptCommands()command factoryAdminScriptBaseclass andScriptFactoryfor script registrationAdminFriggCommandshelper API for scripts (db access, queue, logging)AdminScriptBuilderfor infrastructure generationoauth-token-refresh,integration-health-checkPhase 2: Hybrid Scheduling
ScriptSchedulePrisma modelSchedulerAdapterport interface (hexagonal)AWSSchedulerAdapter(EventBridge Scheduler)LocalSchedulerAdapter(dev/test)Phase 3: Dry-Run Mode
DryRunRepositoryWrapper- intercepts DB writes, logs operationsDryRunHttpInterceptor- mocks HTTP calls, detects 20+ servicesPOST /execute { dryRun: true }supportTest Plan
📦 Published PR as canary version:
2.0.0--canary.517.21b69ac.0✨ Test out this PR locally via:
npm install @friggframework/admin-scripts@2.0.0--canary.517.21b69ac.0 npm install @friggframework/core@2.0.0--canary.517.21b69ac.0 npm install @friggframework/devtools@2.0.0--canary.517.21b69ac.0 npm install @friggframework/eslint-config@2.0.0--canary.517.21b69ac.0 npm install @friggframework/prettier-config@2.0.0--canary.517.21b69ac.0 npm install @friggframework/schemas@2.0.0--canary.517.21b69ac.0 npm install @friggframework/serverless-plugin@2.0.0--canary.517.21b69ac.0 npm install @friggframework/test@2.0.0--canary.517.21b69ac.0 npm install @friggframework/ui@2.0.0--canary.517.21b69ac.0 # or yarn add @friggframework/admin-scripts@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/core@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/devtools@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/eslint-config@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/prettier-config@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/schemas@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/serverless-plugin@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/test@2.0.0--canary.517.21b69ac.0 yarn add @friggframework/ui@2.0.0--canary.517.21b69ac.0