Dependency compatibility checks for Azure. Part of the deployability check.
EOL / Unsupported Runtimes
| Verdict | Condition |
|---|---|
| 🔶 Major Migration | .NET Framework 4.x, ASP.NET Core 2.1, Python 2.x |
| ❌ FAIL or 🔶 | Node.js < 18, Java < 11 — config-only upgrade → ❌ FAIL (fixable), API changes needed → 🔶 |
Quick test: ONE config value change, no import changes? → ❌ FAIL. Otherwise → 🔶.
Ecosystem-era check (Python): ALL pinned deps pre-2018, no Python 3.10+ wheels → ❌ FAIL. Signals: flask_script, werkzeug<1.0, itsdangerous<1.0, imports from werkzeug.contrib.* / flask.ext.*.
EOL / Unmaintained Frameworks
| Verdict | Condition |
|---|---|
| 🔶 Major Migration | Flask < 2.0, Django < 3.2, Express < 4.0, Rails < 6.0, Spring Boot < 2.7 |
| ⚠️ WARN | React < 16, Angular < 14, Next.js < 13 |
Archived / Abandoned Repositories
| Signal | Verdict |
|---|---|
archived: true + EOL stack |
🔶 Major Migration |
archived: true (current runtime) |
⚠️ WARN |
| README "deprecated"/"unmaintained" + EOL | 🔶 Major Migration |
| README "deprecated"/"unmaintained" (current) | ⚠️ WARN |
Remediation scope: Fixing all blockers requires major upgrade OR >5 files → 🔶 Major Migration.
Intentionally Vulnerable Applications
Detect via code structure first, metadata second. These apps are designed to be exploited — vulnerability IS the product.
Code signals (check first):
- Directory
vulnerabilities/with subdirs likesqli/,xss/,csrf/,fi/(file inclusion) - Security-level config toggling vulnerability severity (
default_security_level,security.level,difficulty) - Source files with intentionally unsanitized
$_GET/$_POST/$_REQUESTpassed to SQL queries, shell commands (exec,shell_exec,system), oreval/include-- that are systematic across 3+ files (not a single bug) hackable//exploit/directories, or files with names likecommand_injection.php,brute_force.php
Metadata signals (secondary check):
- Project/package description or repo About containing: "deliberately vulnerable", "intentionally insecure", "vulnerable by design", "security training", "penetration testing", "do not deploy to production"
- README/License warning against internet-facing deployment
Verdict: ≥2 code signals OR 1 code + 1 metadata → 🛑 HALT. Single metadata only → ⚠️ WARN (could be a disclosure).
⛔ 🛑 HALT is a verdict, not an exit. On 🛑 HALT your NEXT action MUST be the Step-4 write — persist all 3 artifacts (
prereq-output.json,context.json,readiness-report.md) withoverallHealth: "blocked"via thecreatetool, then read them back, BEFORE printing any halt summary to the user. A halt message with noprereq-output.jsonon disk is a failure — the deterministicblockedverdict must be persisted first, because the halt message can end the turn.
Non-Azure Cloud SDK Dependencies
Functional cloud SDK deps → 🔶 blockers; classification and observability carve-out in cloud-sdk-migration.md. The redirect gate (SKILL.md Step 2) and the deploy-blocking stop (SKILL.md Step 8 Row 2) own all routing — no routeToSkill decision happens here.
Platform-Specific Dependencies
| Dependency Type | Verdict |
|---|---|
Native OS binaries (.so, .dll) |
⚠️ WARN |
| Native Node.js addons on free/low-tier SKUs | ⚠️ WARN |
| GPU-required libraries (CUDA) | ⚠️ WARN |
| Local file system writes, file-based DBs | ⚠️ WARN — ephemeral on PaaS |
BuildKit Dockerfile syntax (--mount, # syntax=) |
⚠️ WARN W-BUILDKIT — set buildRequirements.hasBuildKitSyntax: true. ACR az acr build does NOT support BuildKit — scaffold must generate Dockerfile.azure. fix: "Generate ACR-compatible Dockerfile.azure" fixPhase: scaffold |
| Jib container build (no Dockerfile) | ⚠️ WARN — note Jib path for scaffold |
| Redis client without TLS config | ⚠️ WARN W-REDIS-TLS — fix: "Add TLS config" fixPhase: prereq. Config key registration: if the app uses a config library that requires keys to be pre-registered before env var override (Go/Viper Unmarshal(), Spring @ConfigurationProperties), the config file must also declare the TLS key (e.g., add tlsEnabled: false to YAML) — otherwise the env var is silently ignored. Detection: grep for viper.Unmarshal, mapstructure, @ConfigurationProperties. |
| PostgreSQL client with SSL disabled | ⚠️ WARN W-PG-SSL — fix: "Set SSL mode env var" fixPhase: scaffold |
| MySQL client without TLS config | ⚠️ WARN W-MYSQL-SSL — fix: "Enable client TLS for Azure MySQL" fixPhase: prereq. Most MySQL drivers/ORMs need an in-code SSL option (no SSL env var like Postgres has), so this is a client-config change → prereq remediation batch (like W-REDIS-TLS), not IaC-only scaffold. Detection: MySQL in the plan (mysql:* in compose, or a MySQL driver/ORM — e.g. mysql2, sequelize dialect mysql, typeorm, prisma, knex) with no SSL/TLS option in the client config. |
| Go Viper without env key replacer | ⚠️ WARN W-VIPER-ENV — fix: "Add SetEnvKeyReplacer call" fixPhase: prereq |
| Licensed/proprietary SDKs | ⚠️ WARN |
Hardcoded Localhost URLs
| Pattern | Verdict | ID | fixPhase |
|---|---|---|---|
localhost, 127.0.0.1, 0.0.0.0 in API base URLs, CORS origins, webhook URLs, service discovery |
⚠️ WARN | W-LOCALHOST-URL |
scaffold |
Exclude: database connection strings, dev-only files, test files.
Dockerfile Analysis
| Pattern | Verdict | ID | fixPhase |
|---|---|---|---|
CMD.*uv run / ENTRYPOINT.*uv run |
⚠️ WARN | W-UV-RUN |
prereq |
CMD.*poetry run / ENTRYPOINT.*poetry run |
⚠️ WARN | W-POETRY-RUN |
prereq |
Also check
docker-compose.ymlcommand:overrides.
Native Module Detection
Static lockfile analysis only.
| Language | Signal | Where |
|---|---|---|
| Node.js | "node-gyp" in lockfile |
package-lock.json, yarn.lock, pnpm-lock.yaml |
| Python | numpy, pandas, grpcio, Pillow, bcrypt, psycopg2 (not -binary), cryptography, lxml, scipy, scikit-learn |
requirements.txt, pyproject.toml |
| .NET | [DllImport], NativeLibrary.Load |
.cs files |
| Go | import "C" (cgo) |
.go files |
| PHP | ext-* requirements |
composer.json |
⛔ Lockfile grep is the ONLY valid evidence. Do NOT set
hasNativeModulesfrom package name alone.prebuild-installwithoutnode-gyp= prebuilt →hasNativeModules: false. Key:bcrypt✅ native,bcryptjs❌ JS.psycopg2✅,psycopg2-binary❌.sharpv0.33+ ❌ prebuilt.canvas✅ always. No lockfile →"unknown", ⚠️ WARN.
When hasNativeModules: true: f1Viable: false, f1BlockReason: "native modules ({signal})".
F1 Viability — Beyond Native Modules
| Condition | f1BlockReason |
|---|---|
| Large dep tree (Python >10, Node lockfile >500KB, .NET >20 NuGet) | "large dependency tree" |
Build-time compilation (tsconfig.json + "build" script) |
"build-time compilation" |
WSGI/ASGI server (gunicorn/uvicorn/daphne) |
"WSGI/ASGI server" |
| 🔶 Major Migration (>5 files) | "major migration" |
When f1Viable: false: prepare selects B1 (~$13/mo) minimum.
First-Run Initialization
Detect init steps needed before first HTTP request — run automatically in dev but cause 500s on Azure.
| Framework | Signal | Init command |
|---|---|---|
| Flask-Migrate/Alembic | flask_migrate/alembic + migrations/ |
flask db upgrade |
| Django | django + manage.py + */migrations/ |
python manage.py migrate |
| Prisma | @prisma/client + prisma/schema.prisma |
npx prisma migrate deploy |
| TypeORM | typeorm + migrations//ormconfig |
npx typeorm migration:run |
| Sequelize | sequelize + migrations/ |
npx sequelize-cli db:migrate |
| EF Core | EntityFrameworkCore.Tools in csproj |
dotnet ef database update |
Seed/bootstrap: Flask @app.cli.command('deploy') → flask deploy. Django fixtures/ → manage.py loaddata. Seed commands: required: false.
Migration framework + migrations/ dir → ⚠️ WARN, write to prereq-output.json.initCommands[] (schema in prereq-schemas.ts). ORM without migrations/ dir → ✅ PASS. Prepare prepends required initCommands to deployStrategy.startupCommand; scaffold encodes in appCommandLine. Migrations are idempotent — safe on every cold start.
Database & Storage
| Found | Assessment |
|---|---|
| File-based DB (SQLite, LevelDB, DuckDB) | ⚠️ WARN — ephemeral on PaaS. Deploy as-is, suggest managed DB in postDeployRecommendations[] |
| Local file storage | Needs Azure Blob Storage |
| In-memory cache only | Consider Redis |
| Managed DB connection string | Ready — update connection |