spinnaker.execution.stages.before.savePipeline

A policy targeting this object runs before executing each task in a savePipeline stage.

This package contains a subset of the functionality found in opa.pipelines. Armory reccomends using the opa.pipelines package instead of this package for most usecases.

Example Payload

Click to expand
{
  "input": {
    "pipeline": {
      "application": "hostname",
      "authentication": {
        "allowedAccounts": [
          "spinnaker",
          "staging",
          "staging-ecs"
        ],
        "user": "myUserName"
      },
      "buildTime": 1620677310519,
      "canceled": false,
      "canceledBy": null,
      "cancellationReason": null,
      "description": "Save pipeline 'scale deployments'",
      "endTime": null,
      "id": "01F5BYAE1QTW4WBT6V3GWRE0KX",
      "initialConfig": {},
      "keepWaitingPipelines": false,
      "limitConcurrent": false,
      "name": null,
      "notifications": [],
      "origin": "unknown",
      "partition": null,
      "paused": null,
      "pipelineConfigId": null,
      "source": null,
      "spelEvaluator": null,
      "stages": [],
      "startTime": 1620677310559,
      "startTimeExpiry": null,
      "status": "RUNNING",
      "systemNotifications": [],
      "templateVariables": null,
      "trigger": {
        "artifacts": [],
        "correlationId": null,
        "isDryRun": false,
        "isRebake": false,
        "isStrategy": false,
        "notifications": [],
        "other": {
          "artifacts": [],
          "dryRun": false,
          "expectedArtifacts": [],
          "notifications": [],
          "parameters": {},
          "rebake": false,
          "resolvedExpectedArtifacts": [],
          "strategy": false,
          "type": "manual",
          "user": "myUserName"
        },
        "parameters": {},
        "resolvedExpectedArtifacts": [],
        "type": "manual",
        "user": "myUserName"
      },
      "type": "ORCHESTRATION"
    },
    "stage": {
      "context": {
        "application": "hostname",
        "notification.type": "savepipeline",
        "pipeline": "eyJhcHBsaWNhdGlvbiI6Imhvc3RuYW1lIiwiZXhwZWN0ZWRBcnRpZmFjdHMiOlt7ImRlZmF1bHRBcnRpZmFjdCI6eyJhcnRpZmFjdEFjY291bnQiOiJzdGVwaGVuYXR3ZWxsIiwiaWQiOiI0YWE4NTE3OC0wNjE4LTQ2YzQtYjUzMC02ODgzZDM5MzY1NmQiLCJuYW1lIjoibWFuaWZlc3RzL2RlcGxveS1zcGlubmFrZXIueWFtbCIsInJlZmVyZW5jZSI6Ikh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3Mvc3RlcGhlbmF0d2VsbC9ob3N0bmFtZS9jb250ZW50cy9tYW5pZmVzdHMvZGVwbG95LXNwaW5uYWtlci55YW1sIiwidHlwZSI6ImdpdGh1Yi9maWxlIiwidmVyc2lvbiI6Im1hc3RlciJ9LCJkaXNwbGF5TmFtZSI6Imhvc3RuYW1lLWRlcGxveSIsImlkIjoiMGNmOTgwMzItMWIwZi00OGRiLTkzMTQtMDljNjkyOTNiM2E2IiwibWF0Y2hBcnRpZmFjdCI6eyJhcnRpZmFjdEFjY291bnQiOiJzdGVwaGVuYXR3ZWxsIiwiY3VzdG9tS2luZCI6dHJ1ZSwiaWQiOiIzZjcyZWQ4ZS1jYjk1LTQ1NGYtOTExOS0yMzIzNjgyMTIxZmYiLCJuYW1lIjoibWFuaWZlc3RzL2RlcGxveS1zcGlubmFrZXIueWFtbCIsInR5cGUiOiJnaXRodWIvZmlsZSJ9LCJ1c2VEZWZhdWx0QXJ0aWZhY3QiOnRydWUsInVzZVByaW9yQXJ0aWZhY3QiOmZhbHNlfSx7ImRlZmF1bHRBcnRpZmFjdCI6eyJhcnRpZmFjdEFjY291bnQiOiJzdGVwaGVuYXR3ZWxsIiwiaWQiOiJlNzkxNjJhYi02OWNiLTRmZjctYWNmNC1hOGYyODc1ZWY4ZWYiLCJuYW1lIjoibWFuaWZlc3RzL3NlcnZpY2Utc3Bpbm5ha2VyLnlhbWwiLCJyZWZlcmVuY2UiOiJIdHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL3N0ZXBoZW5hdHdlbGwvaG9zdG5hbWUvY29udGVudHMvbWFuaWZlc3RzL3NlcnZpY2Utc3Bpbm5ha2VyLnlhbWwiLCJ0eXBlIjoiZ2l0aHViL2ZpbGUifSwiZGlzcGxheU5hbWUiOiJzZXJ2aWNlLWhvc3RuYW1lIiwiaWQiOiI0MjVkMjBhOC0yOTQyLTQ5MDItOGQyYi0yNzc3NjlhMTQ5MmMiLCJtYXRjaEFydGlmYWN0Ijp7ImFydGlmYWN0QWNjb3VudCI6InN0ZXBoZW5hdHdlbGwiLCJjdXN0b21LaW5kIjp0cnVlLCJpZCI6ImQ3YWM3ZWNhLTAxMzEtNGQ1NC1hYjhmLTg4MGZmMDA0MWU0ZiIsIm5hbWUiOiJtYW5pZmVzdHMvc2VydmljZS1zcGlubmFrZXIiLCJ0eXBlIjoiZ2l0aHViL2ZpbGUifSwidXNlRGVmYXVsdEFydGlmYWN0Ijp0cnVlLCJ1c2VQcmlvckFydGlmYWN0IjpmYWxzZX1dLCJpZCI6IjdkYjFlMzUwLWRlZGItNGRjMS05OTc2LWU3MWY5N2I1ZjEzMiIsImluZGV4IjowLCJrZWVwV2FpdGluZ1BpcGVsaW5lcyI6ZmFsc2UsImxhc3RNb2RpZmllZEJ5Ijoic3RlcGhlbmF0d2VsbCIsImxpbWl0Q29uY3VycmVudCI6dHJ1ZSwibmFtZSI6InNjYWxlIGRlcGxveW1lbnRzIiwicGFyYW1ldGVyQ29uZmlnIjpbeyJkZWZhdWx0IjoiIiwiZGVzY3JpcHRpb24iOiIiLCJoYXNPcHRpb25zIjpmYWxzZSwibGFiZWwiOiIiLCJuYW1lIjoicmVwbGljYXMiLCJvcHRpb25zIjpbeyJ2YWx1ZSI6IiJ9XSwicGlubmVkIjpmYWxzZSwicmVxdWlyZWQiOmZhbHNlfSx7ImRlZmF1bHQiOiJzdGFnaW5nIiwiZGVzY3JpcHRpb24iOiIiLCJoYXNPcHRpb25zIjpmYWxzZSwibGFiZWwiOiIiLCJuYW1lIjoibmFtZXNwYWNlIiwib3B0aW9ucyI6W3sidmFsdWUiOiIifV0sInBpbm5lZCI6ZmFsc2UsInJlcXVpcmVkIjp0cnVlfV0sInNwZWxFdmFsdWF0b3IiOiJ2NCIsInN0YWdlcyI6W3siYWNjb3VudCI6InNwaW5uYWtlciIsImNsb3VkUHJvdmlkZXIiOiJrdWJlcm5ldGVzIiwibWFuaWZlc3RBcnRpZmFjdElkIjoiMGNmOTgwMzItMWIwZi00OGRiLTkzMTQtMDljNjkyOTNiM2E2IiwibW9uaWtlciI6eyJhcHAiOiJob3N0bmFtZSJ9LCJuYW1lIjoiRGVwbG95IChNYW5pZmVzdCkiLCJyZWZJZCI6IjIiLCJyZXF1aXNpdGVTdGFnZVJlZklkcyI6W10sInNraXBFeHByZXNzaW9uRXZhbHVhdGlvbiI6ZmFsc2UsInNvdXJjZSI6ImFydGlmYWN0IiwidHJhZmZpY01hbmFnZW1lbnQiOnsiZW5hYmxlZCI6ZmFsc2UsIm9wdGlvbnMiOnsiZW5hYmxlVHJhZmZpYyI6ZmFsc2UsInNlcnZpY2VzIjpbXX19LCJ0eXBlIjoiZGVwbG95TWFuaWZlc3QifSx7ImFjY291bnQiOiJzcGlubmFrZXIiLCJjbG91ZFByb3ZpZGVyIjoia3ViZXJuZXRlcyIsIm1hbmlmZXN0QXJ0aWZhY3RJZCI6IjQyNWQyMGE4LTI5NDItNDkwMi04ZDJiLTI3Nzc2OWExNDkyYyIsIm1vbmlrZXIiOnsiYXBwIjoiaG9zdG5hbWUifSwibmFtZSI6IkRlcGxveSBzZXJ2aWNlIChNYW5pZmVzdCkiLCJyZWZJZCI6IjMiLCJyZXF1aXNpdGVTdGFnZVJlZklkcyI6W10sInNraXBFeHByZXNzaW9uRXZhbHVhdGlvbiI6ZmFsc2UsInNvdXJjZSI6ImFydGlmYWN0IiwidHJhZmZpY01hbmFnZW1lbnQiOnsiZW5hYmxlZCI6ZmFsc2UsIm9wdGlvbnMiOnsiZW5hYmxlVHJhZmZpYyI6ZmFsc2UsInNlcnZpY2VzIjpbXX19LCJ0eXBlIjoiZGVwbG95TWFuaWZlc3QifSx7ImNvbXBsZXRlT3RoZXJCcmFuY2hlc1RoZW5GYWlsIjpmYWxzZSwiY29udGludWVQaXBlbGluZSI6dHJ1ZSwiZmFpbFBpcGVsaW5lIjpmYWxzZSwiaW5zdHJ1Y3Rpb25zIjoiaXMgdGhlIG5ldyBzZXJ2aWNlIHdvcmtpbmc/IiwianVkZ21lbnRJbnB1dHMiOltdLCJuYW1lIjoiTWFudWFsIEp1ZGdtZW50Iiwibm90aWZpY2F0aW9ucyI6W10sInJlZklkIjoiNCIsInJlcXVpc2l0ZVN0YWdlUmVmSWRzIjpbIjIiLCIzIl0sInN0YWdlVGltZW91dE1zIjo2MDAwMCwidHlwZSI6Im1hbnVhbEp1ZGdtZW50In0seyJhY2NvdW50Ijoic3Bpbm5ha2VyIiwiYXBwIjoiaG9zdG5hbWUiLCJjbG91ZFByb3ZpZGVyIjoia3ViZXJuZXRlcyIsImxvY2F0aW9uIjoic3RhZ2luZyIsIm1hbmlmZXN0TmFtZSI6ImRlcGxveW1lbnQgaG9zdG5hbWUiLCJtb2RlIjoic3RhdGljIiwibmFtZSI6IlNjYWxlIChNYW5pZmVzdCkiLCJyZWZJZCI6IjUiLCJyZXBsaWNhcyI6IjEwIiwicmVxdWlzaXRlU3RhZ2VSZWZJZHMiOlsiNCJdLCJ0eXBlIjoic2NhbGVNYW5pZmVzdCJ9XSwidHJpZ2dlcnMiOlt7ImJyYW5jaCI6Im1hc3RlciIsImVuYWJsZWQiOnRydWUsImV4cGVjdGVkQXJ0aWZhY3RJZHMiOlsiMGNmOTgwMzItMWIwZi00OGRiLTkzMTQtMDljNjkyOTNiM2E2IiwiNDI1ZDIwYTgtMjk0Mi00OTAyLThkMmItMjc3NzY5YTE0OTJjIl0sInByb2plY3QiOiJzdGVwaGVuYXR3ZWxsIiwic2VjcmV0Ijoic3Bpbm5ha2VyIiwic2x1ZyI6Imhvc3RuYW1lIiwic291cmNlIjoiZ2l0aHViIiwidHlwZSI6ImdpdCJ9XSwidXBkYXRlVHMiOiIxNjIwNDE5OTQ2MDAwIn0=",
        "pipeline.id": "7db1e350-dedb-4dc1-9976-e71f97b5f132",
        "pipeline.name": "scale deployments",
        "staleCheck": true,
        "user": "myUserName"
      },
      "endTime": null,
      "id": "01F5BYAE1Q1GFVPXQM49ZS0XXQ",
      "lastModified": null,
      "name": "savePipeline",
      "outputs": {},
      "parentStageId": null,
      "refId": "0",
      "requisiteStageRefIds": [],
      "scheduledTime": null,
      "startTime": 1620677310574,
      "startTimeExpiry": null,
      "status": "RUNNING",
      "syntheticStageOwner": null,
      "tasks": [
        {
          "endTime": 1620677311043,
          "id": "1",
          "implementingClass": "com.netflix.spinnaker.orca.front50.tasks.SavePipelineTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "savePipeline",
          "stageEnd": false,
          "stageStart": true,
          "startTime": 1620677310632,
          "status": "SUCCEEDED"
        },
        {
          "endTime": null,
          "id": "2",
          "implementingClass": "com.netflix.spinnaker.orca.front50.tasks.MonitorFront50Task",
          "loopEnd": false,
          "loopStart": false,
          "name": "waitForPipelineSave",
          "stageEnd": true,
          "stageStart": false,
          "startTime": 1620677311058,
          "status": "RUNNING"
        }
      ],
      "type": "savePipeline"
    },
    "user": {
      "isAdmin": false,
      "roles": [],
      "username": "myUserName"
    }
  }
}

Example policy

This policy allows you to restrict which named users can edit which pipelines for which applications. Any pipeline not explicitly specified in the policy is editable as usual.

package spinnaker.execution.stages.before.savePipeline
    
    # This map specifies the name of the app, the name of the pipeline, and a list of users that can edit it.
    allowed_editors:=[{"app":"myAppName","name": "myPipelineName","users":["myUsername"]},{"app":"app","name": "name1","users":[]}]
    
    deny["You do not have permission to edit this pipeline."]{
       not canEdit(input.user.username)      
    }   
      
    default allowedEditors=null
    
    allowedEditors = val{
      pipeline := json.unmarshal(base64.decode(input.stage.context.pipeline))
      some i
      pipeline.name==allowed_editors[i].name
      pipeline.application==allowed_editors[i].app
      val=allowed_editors[i].users    
    }
        
    canEdit(user){
    	allowedEditors[_]==user
    }{ #allow editing any apps/pipelines for which rules have not been defined.
        allowedEditors==null
    }

Keys

Parameters related to the stage against which the policy is executing can be found in the input.stage.context object.

input.pipeline

KeyTypeDescription
input.pipeline.applicationstringThe name of the Spinnaker application for this pipeline.
input.pipeline.authentication.allowedAccounts.[]string[array] of accounts Spinnaker is authorized to access.
input.pipeline.authentication.userstringThe Spinnaker user initiating the change.
input.pipeline.buildTimenumber
input.pipeline.canceledboolean
input.pipeline.canceledBy
input.pipeline.cancellationReason
input.pipeline.descriptionstringDescription of the pipeline defined in the UI.
input.pipeline.endTime
input.pipeline.idstringThe unique ID of the pipeline.
input.pipeline.keepWaitingPipelinesbooleanIf false and concurrent pipeline execution is disabled, then the pipelines in the waiting queue gets canceled when the next execution starts.
input.pipeline.limitConcurrentbooleanTrue if only 1 concurrent execution of this pipeline is allowed.
input.pipeline.nameThe name of this pipeline.
input.pipeline.originstring
input.pipeline.partition
input.pipeline.paused
input.pipeline.pipelineConfigId
input.pipeline.source
input.pipeline.spelEvaluatorWhich version of spring expression language is being used to evaluate SpEL.
input.pipeline.stages[][array]An array of the stages in the pipeline. Typically if you are writing a policy that examines multiple pipeline stages, it is better to write that policy against either the opa.pipelines package, or the spinnaker.execution.pipelines.before package.
input.pipeline.startTimenumberTimestamp from when the pipeline was started.
input.pipeline.startTimeExpiryUnix epoch date at which the pipeline expires.
input.pipeline.statusstring
input.pipeline.templateVariables
input.pipeline.typestring

input.pipeline.trigger

See input.pipeline.trigger for more information.

input.stage

See input.stage for more information.

input.stage.context

KeyTypeDescription
input.stage.context.applicationstringThe name of the Spinnaker application for this pipeline.
input.stage.context.notification.typestringWhat type of spinnaker stage is this.
input.stage.context.pipelinestringa base 64 encoded json represenation of the pipeline that is being saved.
input.stage.context.pipeline.idstring
input.stage.context.pipeline.namestringThe name of this pipeline.
input.stage.context.staleCheckboolean
input.stage.context.userstringThe Spinnaker user initiating the change.

input.user

This object provides information about the user performing the action. This can be used to restrict actions by role. See input.user for more information.


Last modified March 3, 2023: (2d069084)