Skip to main content

Entity Type Classification — OAA Specialist

Date: 2026-02-13 (Round 5) Role: Veza OAA Specialist Core Question: What entity type should Business Rules, Script Includes, REST Messages, OAuth Profiles, Flow Designer Flows, and Scheduled Jobs actually be? Is the current entity_type: "identity" classification correct?


Table of Contents

  1. Executive Summary
  2. The Identity Test — Applied Rigorously
  3. OAA Entity Classification for Each Artifact
  4. The Dual-Nature Problem — Critical Examination
  5. How Other Platforms Classify These Artifacts
  6. Proposed Decision Tree
  7. Proposed Type System
  8. Relationship Implications
  9. The "Runs As" Relationship as the Bridge
  10. Impact on Execution Path Traversal
  11. Impact on Findings and Evidence
  12. OAA Export Implications
  13. Migration Path
  14. Open Questions
  15. Recommendation
  16. Appendix A: Complete Entity Classification Matrix
  17. Appendix B: OAA Community Connector Entity Classification Evidence
  18. Appendix C: Comparison with Current Model

1. Executive Summary

The current model is wrong. After rigorous application of both the Identity Test (authentication, authorization context, audit actor, ACL subject) and OAA's own entity semantics, I conclude:

  • Business Rules, Script Includes, REST Messages, and OAuth Profiles are NOT identities. They fail 4/4 identity criteria. They are artifacts — configurable things that exist within a platform, owned and managed by administrators, acted upon by platform processes.

  • Flow Designer Flows and Scheduled Jobs are NOT identities either, though they come closer. They have a "run as" configuration, which gives them an indirect relationship to an identity. But the flow itself does not authenticate. The identity it runs as authenticates. The flow is an automation artifact that delegates execution to a real identity.

  • OAuth Profiles are credentials, not identities. An OAuth profile stores client_id, client_secret, token_url — it is authentication material, analogous to a certificate or API key. In SecurityV0's own data model, this maps to the existing credential entity type.

The founder's instinct is correct. The Round 4 Architect's claim that "automations are simultaneously identities AND resources" was a rationalization to avoid model change. This round provides the evidence.

Proposed Classification

ArtifactCurrent TypeCorrect TypeOAA Mapping
Service Principalautonomous_identityautonomous_identityLocal User
Machine Accountautonomous_identityautonomous_identityLocal User
Business Ruleautonomous_identity (subtype)automation_artifactResource
Script Includeautonomous_identity (subtype)automation_artifactResource
Flow Designer Flowautonomous_identity (subtype)automation_artifactResource
Scheduled Jobautonomous_identity (subtype)automation_artifactResource
REST Messageautonomous_identity (subtype)automation_artifactResource
OAuth Profileautonomous_identity (subtype)credentialCustom Property on Local User
System Executionautonomous_identity (subtype)autonomous_identityLocal User

2. The Identity Test — Applied Rigorously

The prompt provides a 4-criterion Identity Test. Let me apply each criterion to each artifact with evidence, not assertion.

2.1 Criterion 1: Authenticates (Has Credentials)

What this means: The entity presents credentials (password, certificate, token, API key) to a system to prove it is who it claims to be. The system verifies the credential and establishes a session or grants access.

ArtifactAuthenticates?Evidence
Service PrincipalYESHas client_id + client_secret or certificate. Presents them to Entra's token endpoint. Receives an access token. Appears in sign-in logs with authentication details.
Machine Account (svc-integration-user)YESHas a username + password (or token). Logs into ServiceNow. Session established. Appears in sys_user_session table.
Business RuleNOA Business Rule has no credentials. It does not log in. It is triggered by a database event (insert, update, delete on a table). When it executes, it runs in the context of whatever session triggered it, or in the "system" context. The BR itself presents no credentials.
Script IncludeNOA Script Include is a reusable code library. It is called by other server-side scripts (BRs, Flows, Scheduled Jobs). It has no credentials, no authentication context. It inherits the caller's execution context.
REST MessageNOA REST Message is a configuration artifact — it defines an HTTP endpoint URL, method, headers, and body template. It does not authenticate. When invoked by a script, it may use an authentication profile (OAuth, basic auth, mutual auth) configured separately. The REST Message itself is not an identity.
OAuth ProfileNO — and critically, it is not an identity that authenticates, it is authentication material used BY an identityAn OAuth Profile stores client_id, client_secret, token_url, scope. It is a credential configuration. It does not authenticate itself — it enables authentication. The distinction is: a certificate does not authenticate; an identity presents a certificate to authenticate. Same with an OAuth Profile.
Flow Designer FlowNOA Flow does not authenticate. It has a "Run As" configuration that specifies which user or system context it executes under. That user authenticates. The Flow is an orchestration artifact.
Scheduled JobNOSame as Flow. A Scheduled Job has a "Run As" field. The job definition does not authenticate — the configured user authenticates.

Summary: Only Service Principals and Machine Accounts authenticate. Everything else either has no authentication context or borrows it from a real identity.

2.2 Criterion 2: Has Its Own Authorization Context (Roles, Permissions)

What this means: The entity is directly assigned roles or permissions. When a system evaluates "can X do Y?", X is this entity.

ArtifactHas own authz?Evidence
Service PrincipalYESDirectly assigned roles in Entra (Application.ReadWrite.All, etc.). The SP's access token carries these claims.
Machine AccountYESDirectly assigned roles in ServiceNow (itil, hr_admin, etc.) via sys_user_has_role.
Business RuleNOA BR is not assigned roles. It has an "Advanced" security check (sys_security_acl evaluation), but that check evaluates the session user's roles, not the BR's roles. A BR has no sys_user_has_role entries.
Script IncludeNOA Script Include has no roles. It executes with whatever privileges its caller has. The isAccessible() method on Script Includes checks the caller's roles.
REST MessageNOA REST Message has no roles or permissions. It is a configuration record.
OAuth ProfileNOAn OAuth Profile stores scopes (like "openid", "user.read"), but these are the requested scopes for the token request, not roles assigned to the profile itself. The profile is a credential template.
Flow Designer FlowPARTIALLY — but indirectlyA Flow has a "Run As" configuration. If "Run As" is set to "System User", the flow executes with system-level privileges. But these are not roles assigned to the Flow — they are roles of the user it runs as. The Flow does not appear in sys_user_has_role.
Scheduled JobPARTIALLY — but indirectlySame as Flow. A Scheduled Job's "Run As User" field points to a real user. That user has roles. The job does not have its own roles.

Summary: Only Service Principals and Machine Accounts have their own authorization context. Flows and Scheduled Jobs have indirect authorization via their "Run As" target, but this is delegation, not direct authorization.

2.3 Criterion 3: Appears as the Actor in Audit Logs

What this means: When you look at audit logs, security logs, or transaction logs, this entity appears as the "who" — the actor that performed the action.

ArtifactActor in logs?Evidence
Service PrincipalYESAppears in Entra sign-in logs (servicePrincipalId). Appears in ServiceNow syslog_transaction if it authenticates via OAuth to ServiceNow.
Machine AccountYESAppears in syslog_transaction.user_name, sys_audit.user, sys_user_session. The machine account IS the actor.
Business RulePARTIALLY — as a trigger, not as an actorIn sys_audit, the actor is the user whose action triggered the BR. The BR itself may appear in the source field (e.g., "Business Rule: AzureGraphRouter"). But the BR is not the actor — it is the mechanism. The distinction matters: "User admin triggered a change; Business Rule AzureGraphRouter executed in response" is different from "Business Rule AzureGraphRouter performed an action."
Script IncludeNOScript Includes do not appear as actors in logs. They may appear in stack traces or debug logs, but never as the "who."
REST MessageNOREST Messages do not appear as actors. When an outbound REST call is made, the log entry records the user context, not the REST Message definition.
OAuth ProfileNOOAuth Profiles do not appear in logs as actors. The authenticated identity (SP or user) appears.
Flow Designer FlowPARTIALLYIn sys_flow_context, the flow's sys_id appears. But sys_flow_context.started_by references a user. The flow is the process; the user is the actor. Some logs record sys_flow_context.run_as to show which user context the flow used. Again, the flow is mechanism, not actor.
Scheduled JobPARTIALLYIn syslog_transaction, a scheduled job's execution may show the "Run As" user as the actor. The job itself may appear in the source field. Similar to BR — the job is the trigger/mechanism, the user is the actor.

Summary: Service Principals and Machine Accounts ARE actors in logs. BRs, Flows, and Scheduled Jobs are mechanisms/triggers that appear in logs as sources or contexts, but the actual "actor" is the identity they run as. Script Includes, REST Messages, and OAuth Profiles never appear as actors.

2.4 Criterion 4: Can Be the Subject of "Can X Do Y?"

What this means: Can you meaningfully ask "Can this entity do Y?" and get a deterministic answer from the authorization system?

ArtifactSubject of ACL?Evidence
Service PrincipalYES"Can sp-graph-router read Application.ReadWrite.All scope?" — answered by Entra's role assignment check.
Machine AccountYES"Can svc-integration-user write to the incident table?" — answered by ServiceNow's ACL evaluation against the user's roles.
Business RuleNO"Can Business Rule AzureGraphRouter write to the incident table?" — this question does not make sense in ServiceNow's authorization model. A BR does not have roles. The ACL system evaluates the session user, not the BR. A BR is code that runs, not an entity that has permissions.
Script IncludeNOSame reasoning. "Can Script Include AzureGraphHelper call the Graph API?" — this is not an ACL question. The Script Include has no permissions of its own.
REST MessageNO"Can REST Message AzureGraphAPI access graph.microsoft.com?" — this is a configuration question, not an authorization question. The REST Message defines where to call, not whether the caller is allowed.
OAuth ProfileNO"Can OAuth Profile EntraOAuth access Entra?" — again, not an authorization question. The OAuth Profile stores credentials for accessing Entra, but authorization is evaluated for the SP, not the profile.
Flow Designer FlowNO"Can Flow HR_Onboarding create HR cases?" — this is not how ServiceNow evaluates authorization. ServiceNow evaluates "Can [Run As User] create HR cases?" The flow is the what, not the who.
Scheduled JobNOSame reasoning. "Can Scheduled Job NightlySync read CMDB?" — ServiceNow evaluates the Run As User's permissions, not the job's.

2.5 Identity Test Results Summary

ArtifactAuth?Own Authz?Actor?ACL Subject?ScoreIdentity?
Service PrincipalYESYESYESYES4/4YES
Machine AccountYESYESYESYES4/4YES
System ExecutionYES*YESYESYES3-4/4YES
Business RuleNONOPartialNO0.5/4NO
Script IncludeNONONONO0/4NO
REST MessageNONONONO0/4NO
OAuth ProfileNONONONO0/4NO
Flow Designer FlowNOIndirectPartialNO0.5/4NO
Scheduled JobNOIndirectPartialNO0.5/4NO

*System Execution is a platform-level identity (the "system" user context). It authenticates implicitly as the system, has full privileges, and appears as "system" in audit logs.

Verdict: Six of the nine current "identity subtypes" fail the Identity Test categorically. Only Service Principals, Machine Accounts, and System Execution are identities.


3. OAA Entity Classification for Each Artifact

Now I apply OAA's own entity semantics to classify each artifact. OAA defines four entity categories within an Application:

  1. Local User — An identity that authenticates to the application and has permissions
  2. Local Group — A collection of local users for group-based permission assignment
  3. Local Role — A named bundle of permissions
  4. Resource — A domain object that users interact with; something users have permissions ON

The decision is: for each ServiceNow automation artifact, which of these is it?

3.1 Business Rule → OAA Resource

Reasoning:

A Business Rule is a configurable artifact within ServiceNow. It is a thing that administrators create, modify, enable, disable, and delete. Administrators have permissions on Business Rules (create, read, update, delete via sys_script table ACLs). A BR does not have permissions on other things — it does not hold roles or exercise permissions.

In OAA terms:

  • Is it something that a user interacts with? YES — admins configure, enable, disable BRs.
  • Does it have permissions? NO — it has no roles assigned to it.
  • Can users have permissions on it? YES — via sys_script table ACLs (read, write, delete).

Classification: Resource (type: business_rule)

# OAA mapping
servicenow_app.add_resource(
name="AzureGraphRouter",
resource_type="business_rule"
)

Custom properties carry the execution-relevant metadata:

br_resource.set_property("table", "incident")
br_resource.set_property("trigger_condition", "insert")
br_resource.set_property("active", True)
br_resource.set_property("execution_mode", "autonomous")
br_resource.set_property("egress_category", "external")
br_resource.set_property("run_as", "system")

3.2 Script Include → OAA Resource

Reasoning:

A Script Include is a reusable code library in ServiceNow. It is stored in the sys_script_include table. Administrators create, modify, and manage Script Includes. A Script Include has no identity properties — it does not authenticate, hold roles, or appear as an actor.

It is a dependency of other automation artifacts. In execution chain terms, it is called by Business Rules, Flows, or other Script Includes. It is code-as-resource, analogous to a library or module.

Classification: Resource (type: script_include)

In OAA, Script Includes would be sub-resources of the ServiceNow application, potentially nested under the calling automation:

servicenow_app.add_resource(
name="AzureGraphHelper",
resource_type="script_include"
)

3.3 REST Message → OAA Resource

Reasoning:

A REST Message is an outbound HTTP integration configuration stored in sys_rest_message. It defines:

  • Endpoint URL
  • HTTP method
  • Authentication profile (reference to OAuth Profile or basic auth config)
  • Request/response templates

It is a pure configuration artifact. It is not an identity, not a credential, and not executable logic. It is an integration definition — a resource that describes how to reach an external system.

In the execution chain, a REST Message is a dependency of a Script Include or Business Rule — it is the configuration that tells the calling code where and how to make an HTTP request.

Classification: Resource (type: rest_message)

servicenow_app.add_resource(
name="AzureGraphAPI",
resource_type="rest_message"
)

Custom properties:

rm_resource.set_property("endpoint", "https://graph.microsoft.com")
rm_resource.set_property("auth_type", "oauth2")
rm_resource.set_property("auth_profile_ref", "oauth-profile-sys-id")

3.4 OAuth Profile → Credential (SecurityV0) / Custom Property (OAA)

Reasoning:

This is the most nuanced classification. An OAuth Profile stores:

  • Client ID
  • Client Secret (encrypted)
  • Token URL
  • Grant Type
  • Scopes

This is authentication material. In SecurityV0's own data model, there is already a credential entity type that captures exactly this:

Credential: Authentication material that an identity uses to prove itself to a target system — an OAuth client secret, certificate, personal access token, API key, or federation trust.

The OAuth Profile IS a credential. Specifically, it is a credential of type oauth_client_secret with grant_type: "client_credentials". It has issuing_system (Entra ID), target_system (ServiceNow's outbound config), and scopes_granted.

In OAA, credentials have no first-class entity type. The closest mapping is custom properties on the Local User (the SP that uses the credential) or a custom resource type.

Classification: credential (in SecurityV0 NormalizedNodeType) / Resource with type oauth_profile in OAA export

# OAA: model as a resource since OAA has no credential entity
servicenow_app.add_resource(
name="EntraOAuth",
resource_type="oauth_profile"
)

But in the internal SecurityV0 model:

{
nodeType: "credential",
properties: {
credential_type: "oauth_client_secret",
grant_type: "client_credentials",
issuing_system: "entra_id",
target_system: "servicenow"
}
}

3.5 Flow Designer Flow → OAA Resource

Reasoning:

A Flow Designer Flow is an orchestration artifact. It defines a sequence of actions (steps) that execute in response to a trigger. It is stored in sys_hub_flow.

The Flow has a "Run As" configuration. This is the key property that makes it seem like an identity — it executes actions. But:

  1. The Flow does not authenticate. The "Run As" user authenticates.
  2. The Flow has no roles. The "Run As" user's roles determine what the flow can do.
  3. The Flow is not the ACL subject. ServiceNow evaluates "Can [Run As User] do X?", not "Can [Flow] do X?"
  4. The Flow appears in logs as the mechanism, not the actor. sys_flow_context.started_by is the actor; the flow is the process.

The Flow is a configurable process — a resource within ServiceNow that defines automation behavior. Administrators create, modify, enable, disable, and delete Flows. Users have permissions on Flows (via table ACLs on sys_hub_flow).

A real-world analogy: A Terraform configuration file is not an identity, even though it provisions infrastructure. The identity is the AWS IAM role that Terraform assumes. The Terraform file is a resource — a code artifact that defines what to do. A Flow is the same: a configuration artifact that defines what to execute, delegating identity to its "Run As" target.

Classification: Resource (type: flow_designer_flow)

servicenow_app.add_resource(
name="HR Onboarding Workflow",
resource_type="flow_designer_flow"
)

Custom properties:

flow_resource.set_property("run_as", "system")
flow_resource.set_property("run_as_user_id", "sys-user-id-xyz")
flow_resource.set_property("trigger_type", "record_created")
flow_resource.set_property("trigger_table", "hr_case")
flow_resource.set_property("active", True)
flow_resource.set_property("execution_mode", "autonomous")

3.6 Scheduled Job → OAA Resource

Reasoning:

A Scheduled Job (sysauto_script or sys_trigger) is a time-triggered automation. It has:

  • A schedule (cron expression or interval)
  • A "Run As" user
  • A script or reference to executable logic

The same reasoning as Flow Designer Flow applies:

  1. The job does not authenticate — its "Run As" user does.
  2. The job has no roles — its "Run As" user's roles apply.
  3. The job is not the ACL subject.
  4. The job appears in logs as the mechanism/trigger, not the actor.

Classification: Resource (type: scheduled_job)

servicenow_app.add_resource(
name="Nightly CMDB Sync",
resource_type="scheduled_job"
)

4. The Dual-Nature Problem — Critical Examination

4.1 The Claim

In Round 4, the Architect stated:

"Automation artifacts are simultaneously identities AND resources. They execute (identity), and they are configured (resource). OAA cannot represent this duality because OAA's world is strictly divided."

4.2 Why This Is Wrong

This claim conflates two distinct things:

  1. "They execute" — Correct, automation artifacts cause execution to happen. But causing execution is not the same as being an identity. A trigger on a database table causes execution. A cron schedule causes execution. A webhook URL causes execution. None of these are identities.

  2. "They are configured" — Correct, they are configurable artifacts that administrators manage. This makes them resources.

The error is in equating "causes execution" with "is an identity." By this logic, a database trigger is an identity. A cron expression is an identity. An event listener is an identity. This leads to absurdity.

The correct decomposition is:

  • The automation artifact (BR, Flow, Job) is a resource — a configurable thing that defines behavior.
  • The identity that the artifact runs as is a separate entity — a user, service principal, or system context.
  • The relationship between them is RUNS_AS — the artifact delegates execution to the identity.

This decomposition is:

  • Semantically correct (the BR is not the identity; the identity is the identity)
  • OAA-compatible (resource with properties, not a local user)
  • Consistent with how every other OAA connector classifies analogous artifacts

4.3 The RUNS_AS Relationship Resolves the "Dual Nature"

The perceived "dual nature" is actually a composition of two entities connected by a relationship:

[Automation Artifact] --RUNS_AS--> [Identity]
(Resource) (autonomous_identity)

This is not duality — it is a graph relationship. The artifact has execution semantics because it delegates to an identity that has authentication and authorization. You do not need to make the artifact an identity to capture this. You need a relationship.

SecurityV0 already has the RUNS_AS relationship type. The current model uses RUNS_AS from one identity to another (automation identity → SP). The corrected model uses RUNS_AS from an automation artifact (resource) to an identity:

[Business Rule: AzureGraphRouter] --RUNS_AS--> [Identity: system]
(automation_artifact) (autonomous_identity)

This is more honest about what is happening in the real system.

4.4 The Rationalization Problem

I believe the "dual nature" claim in Round 4 was a rationalization to avoid the cost of changing the data model. The synthesis states:

"Team recommendation: No. All 6 roles agree to keep the existing type enum stable."

But the question in Round 4 was "how should execution chains map to OAA concepts?" — not "should we change the entity type classification?" The Round 4 team was solving a different problem (execution chains collection + OAA export) and inherited the identity assumption without questioning it.

Round 5's question — "is the current identity classification semantically correct?" — was not addressed by Round 4. The answer is no, it is not.


5. How Other Platforms Classify These Artifacts

5.1 Evidence from Every OAA Community Connector

I have reviewed all 9 OAA community connectors (GitHub, GitLab, Jira, PagerDuty, Bitbucket, Slack, Rollbar, Cerby, Looker). Here is the complete evidence:

Entities classified as Local Users (identities):

ConnectorLocal UsersWhy They Are Identities
GitHubOrg members, outside collaboratorsHave GitHub accounts, authenticate, appear as commit authors
GitLabGitLab usersHave accounts, authenticate, have access levels
JiraAtlassian accountsHave accounts, authenticate, are actors on issues
PagerDutyPagerDuty usersHave accounts, authenticate, are on-call actors
BitbucketWorkspace membersHave Atlassian accounts, authenticate, push code
SlackSlack users, botsHave accounts, authenticate, send messages
RollbarRollbar usersHave accounts, authenticate, manage projects
LookerLooker usersHave accounts, authenticate, run queries

Entities classified as Resources:

ConnectorResourcesWhy They Are Resources
GitHubRepositoriesThings users have permissions on (read, write, admin)
GitLabGroups, ProjectsOrganizational containers users have access levels on
JiraProjectsContainers users have permission schemes on
PagerDutyTeamsOrganizational units users belong to and have roles in
BitbucketProjects, ReposThings users have permissions on (read, write, admin)
RollbarProjectsThings users have access levels on (owner, standard, light, view)
LookerModel Sets, Models, ConnectionsData objects users have permissions on

Entities classified as Automation/Execution artifacts: NONE.

Not a single OAA community connector models:

  • GitHub Actions workflows as Local Users
  • GitLab CI pipelines as Local Users
  • Jira workflows or automations as Local Users
  • PagerDuty escalation policies as Local Users
  • Slack workflow automations as Local Users

If these existed in the connectors, they would be Resources — because they are configurable artifacts that users interact with, not identities that authenticate.

5.2 The GitLab Bot Pattern

GitLab's connector provides a relevant edge case. GitLab bots are modeled as Local Users:

if user_info.get("bot") is True:
local_user.set_property("bot", True)

But note: GitLab bots ARE identities. They have accounts. They authenticate. They appear as actors on merge requests and CI jobs. The bot is a user — an automation identity, not an automation artifact.

This is the distinction: a bot (identity that automates) vs. a workflow (artifact that defines automation). SecurityV0's Service Principals and Machine Accounts are bots — they are identities. Business Rules and Flows are workflows — they are artifacts.

5.3 The Slack Bot Pattern

Similarly, Slack models bots as Local Users with a bot_id property:

if is_bot and bot_id is not None:
oaa_user.set_property("bot_id", bot_id)

Slack bots have accounts, authenticate via tokens, and are actors in channels. They are identities, not artifacts.

5.4 Pattern Summary

Across all 9 OAA connectors, the pattern is consistent and universal:

CategoryOAA ClassificationExamples
Things that authenticate and actLocal UserUsers, bots, service accounts
Things that users interact withResourceRepos, projects, teams, connections
Things that bundle permissionsLocal RoleAdmin, read, write, maintain
Collections of usersLocal GroupTeams, groups, user groups

No connector models automation artifacts (workflows, pipelines, rules, policies) as Local Users. None.


6. Proposed Decision Tree

This decision tree is deterministic. Any developer can follow it to classify a new entity from any source system.

6.1 Primary Classification

START: Given entity E from source system S

Q1: Does E authenticate to S using its own credentials?
(Has username/password, client_id/secret, certificate, token, API key)

YES → Q2: Does E have its own role/permission assignments in S?
(Not inherited, not borrowed — directly assigned)

YES → Q3: Does E appear as the "actor" in S's audit logs?
(Not as a trigger source or mechanism, but as the identity
that performed the action)

YES → IDENTITY (autonomous_identity or human_identity)
NO → IDENTITY (may be a service account with limited logging)

NO → This is unusual. An entity that authenticates but has no
direct permissions may be a credential or a proxy.
→ Q4: Does E store authentication material for other entities?
YES → CREDENTIAL
NO → IDENTITY (edge case — may be a delegated identity)

NO → Q5: Does E store authentication material (secrets, keys, certificates, tokens)?
(client_secret, private_key, api_key, password — not just references)

YES → CREDENTIAL

NO → Q6: Does E define executable behavior (code, workflow, process)?
(Scripts, rules, flows, pipelines, jobs)

YES → Q7: Does E have a "run as" or "execute as" identity?

YES → AUTOMATION_ARTIFACT
(with RUNS_AS relationship to the identity)

NO → AUTOMATION_ARTIFACT
(runs in caller context or system context)

NO → Q8: Is E something that identities have permissions ON?
(A table, API endpoint, configuration, integration)

YES → RESOURCE

NO → Q9: Does E bundle permissions together?

YES → ROLE
NO → RESOURCE (default for classifiable artifacts)

6.2 Application of Decision Tree to Each Artifact

ArtifactQ1 (Auth?)PathResult
Service PrincipalYESQ1→YES, Q2→YES, Q3→YESautonomous_identity
Machine AccountYESQ1→YES, Q2→YES, Q3→YESautonomous_identity
System ExecutionYES*Q1→YES, Q2→YES, Q3→YESautonomous_identity
OAuth ProfileNOQ1→NO, Q5→YEScredential
Business RuleNOQ1→NO, Q5→NO, Q6→YES, Q7→YES (system context)automation_artifact
Script IncludeNOQ1→NO, Q5→NO, Q6→YES, Q7→NO (inherits caller)automation_artifact
REST MessageNOQ1→NO, Q5→NO, Q6→NO (configuration, not executable), Q8→YESresource (integration config)
Flow Designer FlowNOQ1→NO, Q5→NO, Q6→YES, Q7→YES (run as user)automation_artifact
Scheduled JobNOQ1→NO, Q5→NO, Q6→YES, Q7→YES (run as user)automation_artifact

Note on REST Message: A REST Message is a borderline case. It defines how to call an external system (URL, headers, body template), but the executable behavior is in the calling Script Include or Business Rule. I classify it as a resource (specifically, an integration configuration resource) rather than an automation_artifact because it does not define autonomous executable behavior — it defines a reusable HTTP call template that is invoked by other code. However, it could reasonably be classified as automation_artifact with subtype integration_config if the team prefers a broader definition.

6.3 Decision Tree for Future Entities

This tree handles entities SecurityV0 may encounter in future connectors:

Future EntityQ PathClassification
GitHub Actions WorkflowQ1→NO, Q5→NO, Q6→YES, Q7→YES (GITHUB_TOKEN identity)automation_artifact
GitHub AppQ1→YES (has private key + JWT), Q2→YES (permissions), Q3→YESautonomous_identity
AWS Lambda FunctionQ1→NO, Q5→NO, Q6→YES, Q7→YES (execution role)automation_artifact
AWS IAM RoleQ1→YES (can be assumed), Q2→YES (policies), Q3→YESautonomous_identity
Terraform State FileQ1→NO, Q5→NO, Q6→NO, Q8→YESresource
Kubernetes CronJobQ1→NO, Q5→NO, Q6→YES, Q7→YES (service account)automation_artifact
Kubernetes Service AccountQ1→YES (token), Q2→YES (RBAC), Q3→YESautonomous_identity
PagerDuty Escalation PolicyQ1→NO, Q5→NO, Q6→YES (defines escalation), Q7→NOautomation_artifact
Jira WorkflowQ1→NO, Q5→NO, Q6→YES (defines transitions), Q7→NOautomation_artifact

7. Proposed Type System

7.1 New NormalizedNodeType Enum

export type NormalizedNodeType =
| "autonomous_identity" // Service Principals, Machine Accounts, System Execution, GitHub Apps
| "human_identity" // Human owners (unchanged)
| "automation_artifact" // Business Rules, Script Includes, Flows, Scheduled Jobs, REST Messages
| "role" // Roles (unchanged)
| "permission" // Permissions (unchanged)
| "resource" // Tables, APIs, repos, cloud resources (unchanged)
| "credential" // OAuth Profiles, certificates, API keys, PATs (unchanged)
| "execution_evidence"; // Proof of execution (unchanged)

Change from current model: Added automation_artifact. Removed the notion that automation subtypes are identities.

7.2 Subtype System

Each automation_artifact carries a subtype property for classification within the type:

// On nodes with nodeType: "automation_artifact"
interface AutomationArtifactProperties {
// Subtype classification
subtype:
| "business_rule"
| "script_include"
| "rest_message"
| "flow_designer_flow"
| "scheduled_job"
| "integration_config" // REST Message alternative classification
| "github_actions_workflow"
| "lambda_function"
| "kubernetes_cronjob";

// Execution context
execution_mode: "autonomous" | "operator_assisted" | "human_triggered" | "unknown";
security_relevance: "active_external" | "dormant_authority" | "internal_inventory";

// Trigger information
trigger_type?: "schedule" | "event" | "manual" | "api_call" | "record_change";
trigger_table?: string;
trigger_condition?: string;
schedule?: string;

// Run-as reference (resolved via RUNS_AS edge)
run_as_type?: "configured" | "inherited" | "system" | "caller_context";

// Egress information
egress_category?: "none" | "internal" | "external";
destination_domain?: string;

// Lifecycle
active: boolean;
created_by?: string;
last_modified_at?: string;
}

7.3 What Each Type Means

TypeSemanticIdentity Test ScoreOAA MappingExamples
autonomous_identityAn entity that authenticates, holds roles, and acts autonomously4/4 or 3/4Local UserService Principal, Machine Account, GitHub App, K8s Service Account
human_identityA human who owns or manages other entitiesN/A (not tested)IdP IdentityHuman owner, admin, operator
automation_artifactA configurable artifact that defines executable behavior, delegating identity to a "run as" target0-0.5/4ResourceBusiness Rule, Flow, Scheduled Job, Script Include, REST Message
roleA named bundle of permissionsN/ALocal RoleServiceNow roles, Entra roles, AWS policies
permissionA single normalized capability (action + scope)N/ACustom Permissionread on incident, write on hr_case
resourceSomething that identities act uponN/AResourceTables, APIs, repos, buckets
credentialAuthentication material used by an identityN/ACustom Property / ResourceOAuth Profile, certificate, PAT, API key
execution_evidenceImmutable proof of actual executionN/ANot in OAAsyslog_transaction entry, sys_flow_context record

7.4 Why Not More Types?

One might ask: why not add integration_config for REST Messages, or code_library for Script Includes? The answer is parsimony:

  1. automation_artifact covers all executable/configurable automation things — the subtype property provides specificity.
  2. Too many types fragment the query model — every UI filter, API endpoint, and evaluation rule that references nodeType must handle each type.
  3. Subtypes are flexible — new subtypes can be added without breaking the type system. New types require changes everywhere.

The one exception I considered was separating integration_config for REST Messages, since they do not define executable behavior themselves. But since they participate in execution chains and carry security-relevant properties (endpoint URLs, auth references), keeping them under automation_artifact with a descriptive subtype is cleaner.


8. Relationship Implications

8.1 Current Relationships (Identity → Identity Model)

Currently, the execution chain for AzureGraphRouter looks like:

BR:AzureGraphRouter (identity) --RUNS_AS--> Identity:system (identity)
BR:AzureGraphRouter (identity) --TRIGGERS_ON--> Resource:incident_table
BR:AzureGraphRouter (identity) --calls--> SI:AzureGraphHelper (identity)
SI:AzureGraphHelper (identity) --calls--> RM:AzureGraphAPI (identity)
RM:AzureGraphAPI (identity) --AUTHENTICATES_VIA--> Cred:EntraOAuth (credential)

Problems with this:

  • A Business Rule does not RUNS_AS anything. It runs in the triggering context.
  • A Script Include does not authenticate. It is called code.
  • A REST Message does not authenticate. It defines how to make a call.
  • The OAuth Profile is already modeled as a credential, but it was also an identity subtype.

8.2 Corrected Relationships (Artifact → Identity Model)

Artifact:AzureGraphRouter (automation_artifact) --RUNS_AS--> Identity:system (autonomous_identity)
Artifact:AzureGraphRouter (automation_artifact) --TRIGGERS_ON--> Resource:incident_table (resource)
Artifact:AzureGraphRouter (automation_artifact) --CALLS--> Artifact:AzureGraphHelper (automation_artifact)
Artifact:AzureGraphHelper (automation_artifact) --CALLS--> Artifact:AzureGraphAPI (automation_artifact)
Artifact:AzureGraphAPI (automation_artifact) --USES_CREDENTIAL--> Credential:EntraOAuth (credential)
Credential:EntraOAuth (credential) --AUTHENTICATES_TO--> Identity:sp-graph-router (autonomous_identity)
Identity:sp-graph-router (autonomous_identity) --HAS_ROLE--> Role:Application.ReadWrite.All

This is more honest:

  • The BR (artifact) runs in system context (RUNS_AS → system identity)
  • The BR (artifact) calls a Script Include (artifact) — this is a CALLS relationship, not identity delegation
  • The Script Include calls a REST Message (artifact) — again a CALLS relationship
  • The REST Message uses a credential (OAuth Profile) — this is USES_CREDENTIAL
  • The credential authenticates to the external identity — AUTHENTICATES_TO
  • The external identity has roles — HAS_ROLE

8.3 New Edge Type Needed: CALLS

The corrected model requires a CALLS edge type for artifact-to-artifact dependencies:

export type NormalizedEdgeType =
| "OWNED_BY"
| "BELONGS_TO"
| "HAS_ROLE"
| "GRANTS"
| "APPLIES_TO"
| "AUTHENTICATES_TO"
| "AUTHENTICATES_VIA"
| "EXECUTES_ON"
| "RUNS_AS" // automation_artifact → autonomous_identity
| "TRIGGERS_ON" // automation_artifact → resource
| "CREATED_BY"
| "DELEGATES_TO"
| "APPROVED_BY"
| "MEMBER_OF"
| "CALLS" // NEW: automation_artifact → automation_artifact
| "USES_CREDENTIAL"; // NEW: automation_artifact → credential

8.4 Updated RUNS_AS Semantics

Currently: Identity → Identity ("this automation identity executes as this identity") Corrected: automation_artifact → autonomous_identity ("this artifact executes in this identity's context")

The semantics are the same, but the source entity type changes from identity to artifact. The path materializer follows the same traversal logic.


9. The "Runs As" Relationship as the Bridge

The RUNS_AS relationship is the key architectural element that makes this classification work. It bridges the gap between artifacts (which define behavior) and identities (which have authorization).

9.1 How RUNS_AS Enables Execution Path Traversal

The execution path question is: "What can this automation ultimately do?"

With the corrected model:

Artifact:AzureGraphRouter
--RUNS_AS--> Identity:system
--HAS_ROLE--> Role:admin
--GRANTS--> Permission:*
--APPLIES_TO--> Resource:* (all tables)

Artifact:AzureGraphRouter
--CALLS--> Artifact:AzureGraphHelper
--CALLS--> Artifact:AzureGraphAPI
--USES_CREDENTIAL--> Credential:EntraOAuth
--AUTHENTICATES_TO--> Identity:sp-graph-router
--HAS_ROLE--> Role:Application.ReadWrite.All
--GRANTS--> Permission:read_write on scope:application
--APPLIES_TO--> Resource:Microsoft Graph API

The path materializer follows:

  1. From the artifact, find RUNS_AS → get the local identity's execution path
  2. From the artifact, follow CALLS → CALLS → USES_CREDENTIAL → AUTHENTICATES_TO → get the cross-system execution path
  3. Union the results = complete blast radius

9.2 RUNS_AS Variants

Run As TypeMeaningExample
configuredExplicitly configured "Run As" userFlow with "Run As: svc-integration-user"
systemRuns in system context (highest privilege)Business Rule running as "system"
inheritedInherits the triggering user's contextBusiness Rule in "current" user context
caller_contextRuns in the calling artifact's contextScript Include called by a Business Rule

For inherited and caller_context types, RUNS_AS is optional or points to a placeholder "session_user" identity. The actual execution authority depends on who/what triggered the chain.


10. Impact on Execution Path Traversal

10.1 Current Path Traversal (Identity Model)

Artifact-as-Identity → RUNS_AS → Identity → HAS_ROLE → ...

The path materializer starts at an "identity" node and follows RUNS_AS to "borrow" another identity's execution paths.

10.2 Corrected Path Traversal (Artifact Model)

automation_artifact → RUNS_AS → autonomous_identity → HAS_ROLE → ...
automation_artifact → CALLS → automation_artifact → USES_CREDENTIAL → credential → AUTHENTICATES_TO → autonomous_identity → HAS_ROLE → ...

The path materializer starts at an artifact node and follows:

  1. RUNS_AS → to get the local execution authority
  2. CALLS → to traverse the dependency chain
  3. USES_CREDENTIAL → to find the authentication material
  4. AUTHENTICATES_TO → to reach the cross-system identity
  5. HAS_ROLE → to get the target system's permissions

10.3 What Changes in the Path Materializer

The path materializer needs to know that automation_artifact nodes are traversal starting points, just like autonomous_identity nodes. Specifically:

  1. Entry point expansion: When listing "things that have execution paths", include both autonomous_identity and automation_artifact nodes.
  2. Edge traversal: Add CALLS and USES_CREDENTIAL to the set of edges the materializer follows.
  3. Depth budget: CALLS edges should consume the depth budget (they are internal dependency chains). RUNS_AS should not (it is identity binding, as per the current model).

10.4 Impact on Existing Queries

Any query that currently selects nodeType: "autonomous_identity" to find "things that execute" will need to also include nodeType: "automation_artifact". This is a breaking change, but the prompt states:

CONSTRAINT: Do NOT consider migration cost. The team has no active clients and can rewrite from scratch if needed. Focus ONLY on semantic correctness.

Therefore, the breaking change is acceptable.


11. Impact on Findings and Evidence

11.1 Findings Currently Generated for Automation Identities

The current model generates findings like:

  • orphaned_ownership for a Business Rule whose creator left
  • dormant_authority for a Flow that has not executed in 90 days
  • scope_drift for a Scheduled Job whose "Run As" user gained new roles

11.2 How Findings Change

With the corrected model:

Orphaned ownership:

  • Still valid. An automation_artifact can have OWNED_BY edges to owners. If all owners have decayed, the finding fires.
  • The finding text changes from "This identity has no owner" to "This automation artifact has no owner."

Dormant authority:

  • Still valid, but the subject changes. The finding is about the artifact's execution path (via RUNS_AS → identity → roles → permissions → resources).
  • The finding text: "This automation artifact has not executed in 90 days but its execution identity (system) still has admin access to all tables."

Scope drift:

  • The drift occurs on the identity, not the artifact. If the "Run As" identity gains new roles, the artifact's blast radius expands.
  • The finding text: "The identity 'system' that automation 'AzureGraphRouter' runs as gained 3 new roles since last baseline."

11.3 New Finding Types Enabled

The corrected model enables findings that the identity model cannot express:

Artifact misconfiguration:

  • "Automation artifact 'AzureGraphRouter' has execution_mode: autonomous but its Run As identity 'system' has admin access to all tables including restricted resources."

Credential chain exposure:

  • "Automation artifact 'AzureGraphHelper' uses credential 'EntraOAuth' which authenticates as Service Principal 'sp-graph-router' with Application.ReadWrite.All permission — a transitive privilege chain from a Business Rule to Microsoft Graph API admin access."

Artifact-identity binding audit:

  • "12 automation artifacts RUNS_AS identity 'system' — this concentrates all automation risk in a single identity context."

12. OAA Export Implications

12.1 Artifact as OAA Resource

In the OAA export layer (from Round 4's recommendation), automation artifacts map cleanly to Resources:

# ServiceNow as OAA Application
sn_app = CustomApplication("ServiceNow - corp.service-now.com", "ServiceNow")

# Automation artifacts as Resources
sn_app.add_resource("AzureGraphRouter", resource_type="business_rule")
sn_app.add_resource("AzureGraphHelper", resource_type="script_include")
sn_app.add_resource("AzureGraphAPI", resource_type="rest_message")
sn_app.add_resource("HR Onboarding Workflow", resource_type="flow_designer_flow")
sn_app.add_resource("Nightly CMDB Sync", resource_type="scheduled_job")

# Identities as Local Users
sp = sn_app.add_local_user("svc-integration-user")
sp.add_identity("svc-integration-user@corp.service-now.com")

# The "system" identity
system = sn_app.add_local_user("system")

# Permission binding: identity has permissions on automation artifacts
system.add_permission("execute", resources=[
sn_app.resources["AzureGraphRouter"],
sn_app.resources["AzureGraphHelper"]
])

12.2 Custom Properties for SecurityV0-Specific Metadata

# On automation artifact resources
br = sn_app.resources["AzureGraphRouter"]
br.set_property("execution_mode", "autonomous")
br.set_property("security_relevance", "active_external")
br.set_property("trigger_type", "record_change")
br.set_property("trigger_table", "incident")
br.set_property("run_as_user", "system")
br.set_property("egress_category", "external")
br.set_property("destination_domain", "graph.microsoft.com")
br.set_property("sv0_artifact_subtype", "business_rule")

12.3 Compatibility

This OAA mapping is more compatible than the current model because:

  1. It follows the same pattern as every existing OAA connector (domain objects as Resources).
  2. It does not create entity proliferation (no micro-Applications).
  3. It preserves SecurityV0-specific semantics via custom properties.
  4. It works with Veza's authorization graph natively (Identity → Permission → Resource).

13. Migration Path

Although the prompt says to ignore migration cost, I will briefly note the logical migration steps for completeness, since they demonstrate the feasibility of the change.

13.1 NormalizedNodeType Enum

Add automation_artifact to the union type. No existing types change.

13.2 Connector (sv0-connectors)

In the transformer, nodes currently emitted as:

{
"nodeType": "autonomous_identity",
"properties": {
"identity_type": "business_rule",
...
}
}

Change to:

{
"nodeType": "automation_artifact",
"properties": {
"subtype": "business_rule",
...
}
}

OAuth Profile nodes change from autonomous_identity to credential.

13.3 Ingestion (sv0-platform)

The entity normalizer must accept automation_artifact as a valid nodeType.

13.4 Storage

The entities collection stores entity_type from nodeType. No schema change needed — the field already accepts any string from the union type.

13.5 Path Materializer

Must follow CALLS, USES_CREDENTIAL edges from automation_artifact nodes. Must include automation_artifact as a valid starting point for execution path materialization.

13.6 Evaluator

Findings that reference autonomous_identity for automation subtypes must be updated to reference automation_artifact.

13.7 UI

Filters that show "identities" may need to also show "automation artifacts" depending on the view. The Graph Explorer and Entity Detail components need to handle the new type.

13.8 Tests

All tests that create Business Rule, Script Include, Flow, Scheduled Job, or REST Message nodes with nodeType: "autonomous_identity" must be updated.


14. Open Questions

Q1: Should REST Message be automation_artifact or resource?

Argument for automation_artifact: REST Messages participate in execution chains and carry security-relevant configuration (endpoint URLs, auth references). They are part of the execution flow.

Argument for resource: REST Messages do not define executable behavior. They are templates. The executable behavior is in the calling Script Include.

My recommendation: automation_artifact with subtype rest_message. This keeps all execution chain participants under one type, simplifying path traversal. The subtype distinguishes configuration artifacts from executable artifacts.

Q2: Should Script Includes with caller_context execution get RUNS_AS edges?

Analysis: A Script Include that runs in the caller's context does not have its own identity binding. It inherits whatever context called it. A RUNS_AS edge would be misleading because the Script Include does not "run as" a specific identity — it runs as whoever called it.

My recommendation: No RUNS_AS edge for caller_context Script Includes. The path materializer discovers their execution authority by traversing the CALLS chain backward to find the nearest artifact with a RUNS_AS edge.

Q3: Should system_execution remain an autonomous_identity?

Analysis: The "system" user in ServiceNow is a legitimate identity. It has maximum privileges, appears as an actor in logs, and is the effective identity for many automated processes. It is the target of RUNS_AS edges from Business Rules and Flows.

My recommendation: Yes, system_execution should remain autonomous_identity. It is the identity that automation artifacts delegate to. It passes the Identity Test (authenticates as system context, has full roles, appears as actor, is the ACL subject for system-level operations).

Q4: What about automation artifacts that have no RUNS_AS target?

Analysis: Some automation artifacts (like Script Includes or REST Messages) do not have an explicit "Run As" configuration. They inherit their execution context from their caller.

My recommendation: These artifacts have no RUNS_AS edge. Their execution authority is determined by traversing the CALLS chain to the root artifact (the Business Rule, Flow, or Scheduled Job that started the chain), which does have a RUNS_AS edge.


15. Recommendation

15.1 Definitive Answer

Business Rules, Script Includes, REST Messages, Flow Designer Flows, and Scheduled Jobs should be automation_artifact entity types, NOT autonomous_identity subtypes.

OAuth Profiles should be credential entity types, NOT autonomous_identity subtypes.

The evidence is unambiguous:

  1. Identity Test: These artifacts score 0-0.5/4 on the Identity Test. Identities score 3-4/4.

  2. OAA Classification: Every OAA community connector classifies domain artifacts as Resources, never as Local Users. No connector models automation workflows, CI pipelines, or configurable processes as identities.

  3. Semantic Correctness: Classifying a Business Rule as an identity conflates "defines behavior" with "has identity." A database trigger defines behavior. A cron expression defines behavior. A Kubernetes deployment manifest defines behavior. None of these are identities.

  4. The Dual-Nature Claim Is a Rationalization: The Round 4 Architect's claim that automations are "simultaneously identities AND resources" was an argument to avoid model change. The RUNS_AS relationship already resolves the "execution semantics" concern without misclassifying the entity type.

  5. RUNS_AS Is the Bridge: The automation artifact → RUNS_AS → identity relationship gives artifacts their execution authority without making them identities. This is the correct decomposition.

15.2 Changes Required

ComponentChange
NormalizedNodeTypeAdd automation_artifact to the union type
NormalizedEdgeTypeAdd CALLS and USES_CREDENTIAL edge types
Connector (transformer.py)Emit BR, SI, RM, Flow, Job as automation_artifact; emit OAuth Profile as credential
Platform (ingestion)Accept automation_artifact as valid nodeType
Path MaterializerFollow CALLS, USES_CREDENTIAL from artifact nodes; include artifacts as entry points
EvaluatorUpdate finding generators to reference automation_artifact for automation-specific findings
Data Model (01-data-model.md)Document new type with full semantic definition
UIAdd artifact type to Graph Explorer, Entity Detail, DataTable

15.3 What This Does NOT Change

  • The execution_chains collection (Round 3) remains as-is — it stores chain composition regardless of entity types.
  • The OAA export layer (Round 4) works better with this change — artifacts map to Resources naturally.
  • The RUNS_AS relationship continues to exist — its source type changes from identity to artifact.
  • The TRIGGERS_ON relationship continues to exist — same edge, different source type.

Appendix A: Complete Entity Classification Matrix

EntitySource SystemCurrent nodeTypeCurrent SubtypeProposed nodeTypeProposed SubtypeIdentity TestOAA Mapping
Service PrincipalEntra IDautonomous_identityservice_principalautonomous_identityservice_principal4/4Local User
OAuth AppEntra IDautonomous_identityoauth_appautonomous_identityoauth_app4/4Local User
GitHub AppGitHubautonomous_identitygithub_appautonomous_identitygithub_app4/4Local User
Machine AccountServiceNowautonomous_identitymachine_accountautonomous_identitymachine_account4/4Local User
System ExecutionServiceNowautonomous_identitysystem_executionautonomous_identitysystem_execution3-4/4Local User
PATGitHub/SNautonomous_identitypatcredentialpatN/ACustom Property
Business RuleServiceNowautonomous_identitybusiness_ruleautomation_artifactbusiness_rule0.5/4Resource
Script IncludeServiceNowautonomous_identityscript_includeautomation_artifactscript_include0/4Resource
REST MessageServiceNowautonomous_identityrest_messageautomation_artifactrest_message0/4Resource
OAuth ProfileServiceNowautonomous_identityoauth_profilecredentialoauth_client_config0/4Resource
Flow Designer FlowServiceNowautonomous_identityflow_designer_flowautomation_artifactflow_designer_flow0.5/4Resource
Scheduled JobServiceNowautonomous_identityscheduled_jobautomation_artifactscheduled_job0.5/4Resource
Human OwnerEntra/SNhuman_identityhumanhuman_identityhumanN/AIdP Identity
TeamEntra/SNhuman_identityteamhuman_identityteamN/ALocal Group
Business UnitOrghuman_identitybusiness_unithuman_identitybusiness_unitN/AN/A
RoleEntra/SNroleroleN/ALocal Role
PermissionEntra/SNpermissionpermissionN/ACustom Permission
Table/API ResourceServiceNowresourcetable/apiresourcetable/apiN/AResource
CredentialEntra/SNcredentialcredentialN/ACustom Property
Execution EvidenceSN/Entraexecution_evidenceexecution_evidenceN/AN/A

Appendix B: OAA Community Connector Entity Classification Evidence

B.1 GitHub (oaa_github.py)

Entities discovered:

  • Org members → add_local_user() (Local User)
  • Outside collaborators → add_local_user() (Local User)
  • Teams → add_local_group() (Local Group)
  • Repositories → add_resource(resource_type="repository") (Resource)

What is NOT modeled:

  • GitHub Actions workflows — not discovered, not modeled
  • GitHub Apps — not discovered (would be Local User if modeled)
  • Secrets — not discovered (would be credential if modeled)
  • Deployment environments — not discovered (would be Resource)

Key evidence: Repositories are Resources. GitHub does not model any automation/workflow artifact as a Local User.

B.2 GitLab (oaa_gitlab.py)

Entities discovered:

  • Users → add_local_user() (Local User)
  • Bots → add_local_user() with bot: True property (Local User)
  • Groups → add_resource(resource_type="group") (Resource)
  • Projects → add_sub_resource(resource_type="project") (Sub-Resource of Group)

What is NOT modeled:

  • CI/CD pipelines — not discovered, not modeled
  • CI/CD variables (secrets) — not discovered
  • GitLab runners — not discovered

Key evidence: GitLab bots are Local Users because they authenticate (have tokens) and act (push code, merge MRs). Groups and Projects are Resources. No CI/CD artifact is modeled.

B.3 Jira (oaa_jira.py)

Entities discovered:

  • Users → add_local_user() (Local User)
  • Groups → add_local_group() (Local Group)
  • Projects → add_resource(resource_type="project") (Resource)
  • Permission schemes → mapped to roles per project

What is NOT modeled:

  • Jira workflows — not discovered (would be Resource)
  • Jira automations — not discovered (would be Resource)
  • Webhooks — not discovered

Key evidence: Projects are Resources. Users have permissions on Projects. No workflow or automation concept is modeled.

B.4 PagerDuty (oaa_pagerduty.py)

Entities discovered:

  • Users → add_local_user() (Local User)
  • Teams → add_local_group() (Local Group) AND add_resource(resource_type="team") (Resource)

What is NOT modeled:

  • Escalation policies — not discovered (would be Resource/automation_artifact)
  • Schedules — not discovered (would be Resource)
  • Incident workflows — not discovered

Key evidence: Teams are simultaneously groups (for membership) and resources (for permission scoping). No automation concept is modeled. Escalation policies, which are the closest PagerDuty analog to ServiceNow Business Rules, are not modeled at all — and if they were, they would be Resources, not Users.

B.5 Bitbucket (oaa_bitbucket.py)

Entities discovered:

  • Workspace members → add_local_user() (Local User)
  • Groups → add_local_group() (Local Group)
  • Projects → add_resource(resource_type="Project") (Resource)
  • Repos → add_sub_resource(resource_type="Repo") (Sub-Resource of Project)

Key evidence: Bitbucket follows the same pattern as GitHub. Code repositories are Resources. Users are identities. No pipelines or automation artifacts modeled.

B.6 Pattern Across All Connectors

Local User (Identity)Local GroupResourceAutomation Artifact as User
GitHubMembers, collaboratorsTeamsReposNEVER
GitLabUsers, botsGroups, ProjectsNEVER
JiraUsersGroupsProjectsNEVER
PagerDutyUsersTeamsTeamsNEVER
BitbucketMembersGroupsProjects, ReposNEVER
SlackUsers, botsUser GroupsNEVER
RollbarUsersTeamsProjectsNEVER
LookerUsersGroupsModel Sets, Models, ConnectionsNEVER

The evidence is unanimous across 8 connectors spanning 8 different platforms: Automation artifacts are NEVER classified as identities (Local Users) in OAA. They are either Resources or not modeled at all.


Appendix C: Comparison with Current Model

C.1 What the Current Model Gets Right

  1. Service Principals, Machine Accounts, and System Execution are correctly classified as identities. They pass the Identity Test.

  2. The RUNS_AS relationship is correct in concept. The idea that automation things "run as" an identity is architecturally sound. The issue is that both the source and target of RUNS_AS are currently identities, when only the target should be.

  3. The execution_mode and security_relevance properties are correct and should be preserved. These properties are meaningful for automation artifacts — they describe the artifact's behavior, not its identity.

  4. TRIGGERS_ON is correct in concept. Automation artifacts are triggered by events on resources. This relationship should flow from automation_artifactresource.

C.2 What the Current Model Gets Wrong

  1. Six automation artifacts are misclassified as identities. This is the core error.

  2. The identity_type property overloads two different concepts. identity_type: "service_principal" (a real identity type) is on the same field as identity_type: "business_rule" (an artifact type). These are categorically different things.

  3. OAuth Profile is misclassified. It is authentication material (credential), not an identity.

  4. The model cannot distinguish "what has execution authority" from "what is a configurable artifact." Because everything is an identity, you cannot query "show me all identities" without getting Business Rules, Script Includes, and REST Messages in the results. This dilutes the meaning of "identity" to the point of uselessness for compliance and audit purposes.

  5. Blast radius calculations are inflated. Because BRs and SIs are identities with "execution paths," the blast radius includes all artifacts in the chain. In reality, the blast radius should start at the identity (the Run As target) and traverse its permissions — not at the artifact.

C.3 The Identity Count Problem

Current model: A ServiceNow instance with 15 Business Rules, 30 Script Includes, 10 REST Messages, 5 OAuth Profiles, 8 Flows, and 4 Scheduled Jobs produces 72 "identities" plus the actual identities (say 5 Service Principals + 3 Machine Accounts).

Total "identity" count: 80 Actual identity count: 8

When a CISO asks "how many non-human identities does this ServiceNow instance have?", the answer should be 8, not 80. The current model inflates the identity count by 10x with artifacts that are not identities.

Corrected model:

  • autonomous_identity count: 8 (5 SPs + 3 machine accounts)
  • automation_artifact count: 67 (15 BRs + 30 SIs + 10 RMs + 8 Flows + 4 Jobs)
  • credential count: 5 (OAuth Profiles)

The CISO gets the correct answer: 8 non-human identities, 67 automation artifacts that execute through those identities, 5 credentials that enable cross-system authentication.


Round 5 analysis complete. The entity type classification error in the current model is clear, evidence-based, and fixable. The proposed changes (adding automation_artifact type, reclassifying 6 subtypes, reclassifying OAuth Profile as credential) produce a model that is semantically correct, OAA-compatible, and consistent with how every Veza community connector classifies analogous entities. The RUNS_AS relationship remains the bridge between artifacts and identities, preserving execution path traversal. The founder's instinct was right.