Skip to content

v0.6.3-beta ​

A security release. Generating a real multi-tenant project (ProKantar) with 0.6.2 surfaced several holes in the generated code: unauthenticated gRPC, CRUD endpoints that could overwrite workflow-owned fields, free-form sortBy, unescaped search and default database passwords. This release closes them. Most changes are on by default; read Breaking changes before upgrading a production service.

Security ​

Authenticated gRPC ​

  • In services with an auth block, every gRPC endpoint now requires a valid JWT (MapGrpcService<…>().RequireAuthorization()).
  • Generated gRPC clients attach credentials automatically (AddBaseForgeCallCredentials):
    • inside an HTTP request the caller's Bearer token is forwarded, so the callee sees the real user (roles, tenant_id);
    • in background code (RabbitMQ consumers, jobs) a client_credentials service token is fetched from Identity and cached (IServiceTokenProvider).
  • The tenant travels as x-tenant-id metadata, and it is trusted only with a service token: Identity now stamps a bf_svc claim into client-credentials tokens. A user cannot switch tenants by sending the header.
  • New TenantScope (BaseForge.Core.MultiTenancy): an ambient tenant for code that runs outside an HTTP request.

Server-managed fields — serverManaged ​

yaml
status: { type: enum, values: [Open, Completed], serverManaged: true }
netKg:  { type: decimal, nullable: true, serverManaged: true }

The field is left out of the generated Create/Update commands and stays in the DTO. Only your own commands (in Custom/) change it, so status changes and calculated totals can no longer be set by a plain PUT. The Designer has a checkbox for it.

Safe sorting and searching ​

  • sortBy accepts only Field, Field asc or Field desc (comma-separated, at most 5) from an allow-list. The default list is all scalar fields plus CreatedAt/UpdatedAt; set sortFields: [...] to narrow it. Anything else returns 400. GenericRepository refuses TenantId, IsDeleted and DeletedAt on its own.
  • searchFields: [...] limits which text fields search looks in (default: all). Keep sensitive fields such as ID numbers out of it.
  • %, _ and \ in the search term are escaped. Terms shorter than 2 characters are ignored.

Counter endpoints ​

  • New access action: access: { counters: authenticated | [roles] }. Without it, counters stay public as before.
  • increment-* endpoints are rate-limited to 30 requests per minute per user (or IP), and the 31st request gets 429.

Secrets and ports ​

  • Every generated service (and Identity) gets a .env with a random 32-character POSTGRES_PASSWORD, plus a committed .env.example. .env is gitignored and excluded from the Docker image.
  • appsettings.json no longer contains a password. docker-compose.yml reads ${POSTGRES_PASSWORD} and refuses to start without it. Local dotnet run loads .env automatically.
  • Postgres is published on 127.0.0.1 only.
  • Outside Development, a service refuses to start when its database password is empty or change_me.

Breaking changes ​

  • Production with change_me: a non-Development service whose connection string still uses change_me (or an empty password) will not start. Set a real password in .env / the environment first.
  • Existing volumes are kept: when a service generated by 0.6.2 or earlier is regenerated, change_me is detected and kept in .env, so local databases keep working. Rotate it deliberately.
  • sortBy: expressions other than Field [asc|desc], or fields outside the allow-list, now return 400 instead of being executed.
  • Background gRPC calls: to call another service from a consumer or a job, add a confidential client to identity/auth.yaml (clientId: {service}-service, grants: [client_credentials], scopes: [api]) and put its secret in the calling service's .env as Auth__ServiceClient__ClientSecret. Without it, user-initiated calls keep working, but background calls get 401.

Upgrade ​

bash
dotnet tool update -g BaseForge.CodeGen --prerelease
baseforge update <service>   # opens the Designer with the spec loaded → Generate

Regenerated services reference the BaseForge.* 0.6.3-beta packages. Hand-written code under Custom/ is untouched. Details are in the architecture decisions (§5.1.1, §5.5, §6.2, §6.4, §6.5).

Coming next ​

Tenant id in integration events and the consumer, per-entity tenantScoped, tenant-aware unique indexes, tenant management in Identity, range/IN filters with defaultSort, a PostGIS geometry type and Designer guards (stale-form check, port conflicts).

Released under the MIT License.