Persona Policies

Each persona represents a distinct user role with specific access patterns and constraints. The policy system evaluates the user’s roles against these persona definitions to determine authorization.

Persona Summary

Persona

Role Identifier

Read

Create

Update

Delete

Embargo Exempt

Public

(none required)

Limited

No

No

No

No

Dam Operator

dam_operator

Yes

Manual only

Manual only

No

No

Water Manager

water_manager

Yes

Yes

Yes

No

Yes

Data Manager

data_manager

Yes

Yes

Yes

Approved only

Yes

Automated Collector

automated_collector

No

Automated only

No

No

No

Automated Processor

automated_processor

Yes

Calculated only

Calculated only

No

No

External Cooperator

external_cooperator

Limited

Limited

No

No

No

Viewer Users

Viewer Users

Yes

No

No

No

No

Public Access

The public persona allows unauthenticated access to non-sensitive endpoints.

Allowed Operations

System Endpoints (no authentication required):

  • health, ready, metrics

Reference Data (read-only):

  • offices, units, parameters, timezones

Public Timeseries Data:

  • Classification must be public

  • Subject to TS group embargo rules

Public Locations:

  • Classification must be public

Policy Logic

package cwms.personas.public

allow if {
    input.resource in ["health", "ready", "metrics"]
}

allow if {
    input.action == "read"
    input.resource in ["offices", "units", "parameters", "timezones"]
}

allow if {
    input.action == "read"
    input.resource == "timeseries"
    input.context.classification == "public"
    not time_rules.data_under_ts_group_embargo(input.context, input.user)
}

allow if {
    input.action == "read"
    input.resource == "locations"
    input.context.classification == "public"
}

Dam Operator

Dam operators monitor and manually enter operational data for their assigned facilities.

Constraints

Constraint

Value

Office Access

Assigned offices only

Embargo

Subject to TS group embargo

Shift Hours

Create/update restricted to shift hours

Modification Window

Updates limited to 24 hours after creation

Data Source

Manual entries only

Allowed Operations

Read Access:

  • timeseries, measurements, levels, gates, locations

  • Must have office access

  • Subject to embargo rules

Create Access:

  • timeseries, measurements

  • Data source must be MANUAL

  • Must be within shift hours

  • Must have office access

Update Access:

  • timeseries, measurements

  • Data source must be MANUAL

  • Must be within shift hours

  • Resource must be within 24-hour modification window

  • Must have office access

Policy Logic

package cwms.personas.dam_operator

allow if {
    "dam_operator" in input.user.roles
    input.action == "read"
    input.resource in ["timeseries", "measurements", "levels", "gates", "locations"]
    offices.user_can_access_office(input.user, input.context.office_id)
    not time_rules.data_under_ts_group_embargo(input.context, input.user)
}

allow if {
    "dam_operator" in input.user.roles
    input.action == "create"
    input.resource in ["timeseries", "measurements"]
    input.context.data_source == "MANUAL"
    offices.user_can_access_office(input.user, input.context.office_id)
    time_rules.within_shift_hours(input.user)
}

allow if {
    "dam_operator" in input.user.roles
    input.action == "update"
    input.resource in ["timeseries", "measurements"]
    input.context.data_source == "MANUAL"
    offices.user_can_access_office(input.user, input.context.office_id)
    time_rules.within_shift_hours(input.user)
    time_rules.within_modification_window(input.context, input.user)
}

Water Manager

Water managers have broad access for hydrological analysis and forecasting within their assigned offices.

Constraints

Constraint

Value

Office Access

Assigned offices only

Embargo

Exempt

Data Classification

All levels

Allowed Operations

Read Access:

  • timeseries, locations, forecasts, models, scenarios, ratings, levels

  • Must have office access

Create/Update Access:

  • timeseries, locations, forecasts, models, scenarios

  • Must have office access

Policy Logic

package cwms.personas.water_manager

allow if {
    "water_manager" in input.user.roles
    input.action == "read"
    input.resource in ["timeseries", "locations", "forecasts", "models", "scenarios", "ratings", "levels"]
    offices.user_can_access_office(input.user, input.context.office_id)
}

allow if {
    "water_manager" in input.user.roles
    input.action in ["create", "update"]
    input.resource in ["timeseries", "locations", "forecasts", "models", "scenarios"]
    offices.user_can_access_office(input.user, input.context.office_id)
}

Data Manager

Data managers have full data lifecycle control with approval workflows for destructive operations.

Constraints

Constraint

Value

Office Access

Assigned offices and regional offices

Embargo

Exempt

Delete

Requires approval from different user

Allowed Operations

Read/Create/Update Access:

  • timeseries, locations, catalogs, ratings, measurements, levels

  • Must have office access (direct or regional)

Delete Access:

  • timeseries, locations, catalogs, ratings

  • Must have office access

  • Requires approval_status == "approved"

  • Approver must be different from requester

Policy Logic

package cwms.personas.data_manager

allow if {
    "data_manager" in input.user.roles
    input.action in ["read", "create", "update"]
    input.resource in ["timeseries", "locations", "catalogs", "ratings", "measurements", "levels"]
    offices.user_can_access_office(input.user, input.context.office_id)
}

allow if {
    "data_manager" in input.user.roles
    input.action == "delete"
    input.resource in ["timeseries", "locations", "catalogs", "ratings"]
    offices.user_can_access_office(input.user, input.context.office_id)
    input.context.approval_status == "approved"
    input.context.approver_id != input.user.id
}

Automated Collector

Service accounts for automated data collection systems.

Constraints

Constraint

Value

Office Access

Assigned offices only

Authentication

API key required

Data Source

Automated only

Allowed Operations

Create Access:

  • timeseries only

  • Data source must be AUTOMATED

  • Authentication method must be api_key

  • Must have office access

Policy Logic

package cwms.personas.automated_collector

allow if {
    "automated_collector" in input.user.roles
    input.action == "create"
    input.resource == "timeseries"
    input.context.data_source == "AUTOMATED"
    offices.user_can_access_office(input.user, input.context.office_id)
    input.user.auth_method == "api_key"
}

Automated Processor

Service accounts for data processing pipelines that read raw data and write calculated results.

Constraints

Constraint

Value

Office Access

All offices (cross-regional processing)

Embargo

Subject to TS group embargo for reads

Data Source

Read: AUTOMATED/MANUAL, Write: CALCULATED only

Allowed Operations

Read Access:

  • timeseries only

  • Data source must be AUTOMATED or MANUAL

  • Subject to embargo rules

  • No office restriction (cross-regional processing)

Create/Update Access:

  • timeseries only

  • Data source must be CALCULATED

  • Must include calculation_metadata

Policy Logic

package cwms.personas.automated_processor

allow if {
    "automated_processor" in input.user.roles
    input.action == "read"
    input.resource == "timeseries"
    input.context.data_source in ["AUTOMATED", "MANUAL"]
    not time_rules.data_under_ts_group_embargo(input.context, input.user)
}

allow if {
    "automated_processor" in input.user.roles
    input.action in ["create", "update"]
    input.resource == "timeseries"
    input.context.data_source == "CALCULATED"
    input.context.calculation_metadata != null
}

External Cooperator

External partners with limited access governed by partnership agreements.

Constraints

Constraint

Value

Office Access

Assigned offices only

Partnership

Must have active (non-expired) partnership

Parameters

Limited to allowed parameter types

Classification

Cannot access sensitive data

Embargo

Subject to TS group embargo

Allowed Operations

Read Access:

  • timeseries only

  • Parameter must be in user’s allowed_parameters list

  • Classification cannot be sensitive

  • Partnership must be active (not expired)

  • Subject to embargo rules

Create Access:

  • timeseries only

  • Parameter must be in user’s allowed_parameters list

  • Must have office access

  • Partnership must be active

Policy Logic

package cwms.personas.external_cooperator

partnership_active(user) if {
    user.partnership_expiry_ns != null
    user.partnership_expiry_ns > time.now_ns()
}

allow if {
    "external_cooperator" in input.user.roles
    input.action == "read"
    input.resource == "timeseries"
    input.context.parameter in input.user.allowed_parameters
    input.context.classification != "sensitive"
    partnership_active(input.user)
    not time_rules.data_under_ts_group_embargo(input.context, input.user)
}

allow if {
    "external_cooperator" in input.user.roles
    input.action == "create"
    input.resource == "timeseries"
    input.context.parameter in input.user.allowed_parameters
    offices.user_can_access_office(input.user, input.context.office_id)
    partnership_active(input.user)
}

Viewer Users

Read-only users with basic access to data within their assigned offices.

Constraints

Constraint

Value

Office Access

Assigned offices only

Embargo

Subject to TS group embargo

Actions

Read-only

Allowed Operations

Reference Data (read-only, no office restriction):

  • offices, units, parameters, timezones

Operational Data (read-only):

  • timeseries, locations, levels

  • Must have office access

  • Subject to embargo rules

Policy Logic

package cwms.personas.viewer_users

allow if {
    "Viewer Users" in input.user.roles
    input.action == "read"
    input.resource in ["offices", "units", "parameters", "timezones"]
}

allow if {
    "Viewer Users" in input.user.roles
    input.action == "read"
    input.resource in ["timeseries", "locations", "levels"]
    offices.user_can_access_office(input.user, input.context.office_id)
    not time_rules.data_under_ts_group_embargo(input.context, input.user)
}

Policy Matching Logic

When a request arrives, the main orchestrator evaluates each persona policy. The first matching rule grants access:

        graph TD
    request[Request with User Roles] --> checkSysAdmin{Check system_admin}
    checkSysAdmin -->|Yes| allow[Allow]
    checkSysAdmin -->|No| checkHec{Check hec_employee}
    checkHec -->|Yes| allow
    checkHec -->|No| evalPersonas{Evaluate Persona Policies}
    evalPersonas --> matchRoles[Match user.roles to persona]
    matchRoles --> roleMatch{Role matches?}
    roleMatch -->|No| nextPersona[Next persona]
    nextPersona --> evalPersonas
    roleMatch -->|Yes| checkAction{Check action}
    checkAction -->|Invalid| nextPersona
    checkAction -->|Valid| checkResource{Check resource}
    checkResource -->|Invalid| nextPersona
    checkResource -->|Valid| checkConstraints{Check constraints}
    checkConstraints -->|Fail| nextPersona
    checkConstraints -->|Pass| allow
    evalPersonas -->|All exhausted| deny[Deny]
    

Constraint Comparison

Constraint

Public

Dam Op

Water Mgr

Data Mgr

Auto Collect

Auto Process

Ext Coop

Viewer

Embargo Exempt

No

No

Yes

Yes

N/A

No

No

No

Office Restricted

No

Yes

Yes

Yes

Yes

No

Yes

Yes

Shift Hours

No

Yes

No

No

No

No

No

No

Mod Window

No

Yes

No

No

No

No

No

No

API Key Required

No

No

No

No

Yes

No

No

No

Partnership Required

No

No

No

No

No

No

Yes

No

Delete Approval

N/A

N/A

N/A

Yes

N/A

N/A

N/A

N/A