Add hostile fixture setup for authz testing
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"alice_email": "alice.m015@example.com",
|
||||
"bob_email": "bob.m015@example.com",
|
||||
"company_id": 1,
|
||||
"job_id": 1,
|
||||
"correspondence_id": 1,
|
||||
"attachment_id": 1,
|
||||
"api_base": "http://localhost:5202/api"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# M015 Hostile Fixture Setup
|
||||
|
||||
## Goal
|
||||
|
||||
Produce a trustworthy local runtime for cross-user authorization probes.
|
||||
|
||||
## Key discovery
|
||||
|
||||
The default development SQLite database in `JobTrackerApi/jobtracker.db` is **not** a trustworthy authorization-test target:
|
||||
|
||||
- it contains Identity and some later feature tables
|
||||
- it does **not** contain the core domain tables needed for real cross-user job/correspondence/attachment probing
|
||||
- current startup `Migrate()` behavior is therefore insufficient as the only hostile-test setup path
|
||||
|
||||
## Chosen fixture strategy
|
||||
|
||||
Use a dedicated clean SQLite fixture database created from the current EF model with `EnsureCreated()` semantics through a tiny helper program:
|
||||
|
||||
- helper project: `tools/hostile-fixture-db/`
|
||||
- bootstrap script: `scripts/m015-hostile-fixture.sh`
|
||||
|
||||
This keeps the hostile runtime inside repo code and the real API host while avoiding ad-hoc manual SQL.
|
||||
|
||||
## What the helper does
|
||||
|
||||
- creates a clean `jobtracker.db` under a caller-provided data root
|
||||
- builds the schema from the current `JobTrackerContext` model
|
||||
- verifies the presence of core tables needed for M015:
|
||||
- `Companies`
|
||||
- `JobApplications`
|
||||
- `Correspondences`
|
||||
- `Attachments`
|
||||
- `RuleSettings`
|
||||
- `AspNetUsers`
|
||||
|
||||
## Runtime plan for S02
|
||||
|
||||
1. Run `scripts/m015-hostile-fixture.sh`.
|
||||
2. Start the API with `Data__Root` pointing at that clean fixture root.
|
||||
3. Mint an admin dev token against the fixture DB.
|
||||
4. Create/reuse Alice and Bob through real API paths.
|
||||
5. Seed Alice-owned company/job/correspondence/attachment fixtures through the real API.
|
||||
6. Capture ids for cross-user hostile probes.
|
||||
|
||||
## Honest boundary
|
||||
|
||||
This slice establishes the trusted runtime path and fixture strategy. The full two-user seeded dataset and exploit execution belong in the next slice.
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
FIXTURE_ROOT="${FIXTURE_ROOT:-$REPO_ROOT/.tmp/m015-fixture}"
|
||||
API_PORT="${API_PORT:-5202}"
|
||||
API_BASE="http://localhost:${API_PORT}/api"
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
mkdir -p "$FIXTURE_ROOT"
|
||||
|
||||
echo "[m015] creating clean hostile-test db under $FIXTURE_ROOT"
|
||||
dotnet run --project "$REPO_ROOT/tools/hostile-fixture-db/HostileFixtureDb.csproj" -- "$FIXTURE_ROOT" > "$TMP_DIR/db.json"
|
||||
python3 - <<'PY' "$TMP_DIR/db.json"
|
||||
import json, sys
|
||||
payload=json.load(open(sys.argv[1]))
|
||||
required={'Companies','JobApplications','Correspondences','Attachments','RuleSettings','AspNetUsers'}
|
||||
missing=sorted(required-set(payload['tables']))
|
||||
if missing:
|
||||
raise SystemExit(f"missing tables after fixture db init: {', '.join(missing)}")
|
||||
print('[m015] db tables ok')
|
||||
PY
|
||||
|
||||
echo "[m015] ready to start API with:"
|
||||
echo " Data__Root=$FIXTURE_ROOT ASPNETCORE_ENVIRONMENT=Development dotnet run --project JobTrackerApi/JobTrackerApi.csproj"
|
||||
echo "[m015] API base: $API_BASE"
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../JobTrackerBackend/JobTrackerBackend.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,50 @@
|
||||
using JobTrackerApi.Data;
|
||||
using JobTrackerApi.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Text.Json;
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Console.Error.WriteLine("Usage: dotnet run --project tools/hostile-fixture-db -- <data-root>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var dataRoot = Path.GetFullPath(args[0]);
|
||||
Directory.CreateDirectory(dataRoot);
|
||||
var dbPath = Path.Combine(dataRoot, "jobtracker.db");
|
||||
if (File.Exists(dbPath))
|
||||
{
|
||||
File.Delete(dbPath);
|
||||
}
|
||||
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["Data:Root"] = dataRoot,
|
||||
})
|
||||
.Build();
|
||||
|
||||
var currentUser = new StaticCurrentUserService(null);
|
||||
var options = new DbContextOptionsBuilder<JobTrackerContext>()
|
||||
.UseSqlite($"Data Source={dbPath}")
|
||||
.Options;
|
||||
|
||||
await using var db = new JobTrackerContext(options, currentUser);
|
||||
await db.Database.EnsureDeletedAsync();
|
||||
await db.Database.EnsureCreatedAsync();
|
||||
|
||||
var tables = await db.Database.SqlQueryRaw<string>("SELECT name AS Value FROM sqlite_master WHERE type='table' ORDER BY name;").ToListAsync();
|
||||
var payload = new
|
||||
{
|
||||
dataRoot,
|
||||
dbPath,
|
||||
tables,
|
||||
};
|
||||
Console.WriteLine(JsonSerializer.Serialize(payload));
|
||||
return 0;
|
||||
|
||||
file sealed class StaticCurrentUserService(string? userId) : ICurrentUserService
|
||||
{
|
||||
public string? UserId => userId;
|
||||
}
|
||||
Reference in New Issue
Block a user