/projects/airia-spm

All projects

Secure Posture Management

An inventory of every AI agent an enterprise is already running.

R&D Engineer — domain model, persistence and a provider · Jul 2025 – Oct 2025

.NET 9Entity Framework CorePostgreSQLAzure AI FoundryAWS BedrockxUnit
Private
Secure Posture Management screenshot

Overview

Posture management inside the platform: a set of provider connections that are refreshed on a schedule, the agents and components they discover, and the violations feed that says which of them did something a policy forbids.

What I did

I built the domain model and the persistence under this feature, and added one of the cloud providers it discovers through.

  • The entities — connection, agent, component, settings — and their database context.
  • A repository layer over that context, so query logic stopped living in services.
  • The Azure model-service provider, alongside the ones already supported.
  • An execution identifier on the violations feed, tying a violation to the run behind it.

This was a large feature owned across several teams — the discovery scanners, the risk scoring and the interface were other people’s work. Mine is the layer they read and write through.

The problem

An enterprise does not adopt AI in one place. It arrives through a workflow automation tool one team installed, a cloud model service another team already pays for, an assistant builder bundled into software it licenses, and personal subscriptions nobody approved. Governing that starts with a list, and before this feature there was no list — only the parts each team happened to know about.

Architecture

A tenant configures a connection per provider, each with its own typed configuration rather than a shared bag of settings. A scheduled job refreshes those connections and writes back what it found as components and agents, so the inventory has an age rather than being whatever the last person clicked. The violations feed sits on top and, since this work, carries the execution identifier that links a violation to the run that produced it.

  1. Provider connectionOne per platform an enterprise runs AI on, each with a typed configuration of its own.
  2. Scheduled refreshRe-reads every connection on a timer, so the inventory ages instead of going stale silently.
  3. Components and agentsWhat was discovered, persisted through a repository layer rather than ad-hoc queries.
  4. Violations feedWhat broke a policy, each row traceable to the execution that caused it.

What it does

  • Discovery across several agent platforms, each behind its own typed connection.
  • A scheduled refresh, so the inventory has a known age.
  • A repository layer over the database context, keeping query logic out of services.
  • Violations traceable to the execution that produced them.

Engineering decisions

  • A typed configuration per provider, not one settings blob

    Every provider authenticates differently and exposes a different shape of thing to discover. A single loosely-typed settings object would have made every consumer guess which keys apply to which provider, and made adding one a matter of hoping nothing downstream cared. A closed set of typed configurations means the compiler names the work required to support a new platform.

  • A repository layer, added after the fact and on purpose

    The first version queried the database context straight from the services, which is fine until three teams are writing services against the same entities and each invents its own idea of what "the agents for this tenant" means. Moving those queries behind repositories gave the feature one definition of each read, and gave the unit tests something to stand on that is not a database.

  • A scheduled refresh instead of a webhook per provider

    Webhooks would be fresher, and would require every provider to support them, every customer to configure them, and the platform to be reachable from each one — which is the same perimeter problem the connector exists to avoid. Polling on a schedule is less elegant and works everywhere, and an inventory whose age is known is more useful than one that is silently missing whatever event was dropped.

  • A violation you can trace to a run

    A feed saying a policy was broken is an alert; a feed saying which execution broke it is an investigation. Carrying the execution identifier through to the violation row is a one-column change that moves the feed from something a security team watches to something they can act on.