Annotations are grouped within a metadata block, and must be specified as YAML within a comment block that must start with . Also, every line in the comment block containing the annotation must start at Column 1 in the module/file, or otherwise, they will be ignored.

OPA will attempt to parse the YAML document in comments following the initial # METADATA comment. If the YAML document cannot be parsed, OPA will return an error. If you need to include additional comments between the comment block and the next statement, include a blank line immediately after the comment block containing the YAML document. This tells OPA that the comment block containing the YAML document is finished

Annotations can be defined at the rule or package level. The scope annotation in a metadata block determines how that metadata block will be applied. If the scope field is omitted, it defaults to the scope for the statement that immediately follows the annotation. The scope values that are currently supported are:

  • rule - applies to the individual rule statement (within the same file). Default, when metadata block precedes rule.
  • document - applies to all of the rules with the same name in the same package (across multiple files)
  • package - applies to all of the rules in the package (within the same file). Default, when metadata block precedes package.
  • subpackages - applies to all of the rules in the package and all subpackages (recursively, across multiple files)

Since the document scope annotation applies to all rules with the same name in the same package and the subpackages scope annotation applies to all packages with a matching path, metadata blocks with these scopes are applied over all files with applicable package- and rule paths. As there is no ordering across files in the same package, the document and subpackages scope annotations can only be specified once per path. The document scope annotation can be applied to any rule in the set (i.e., ordering does not matter.)

Example

  1. # METADATA
  2. # scope: document
  3. # description: A set of rules that determines if x is allowed.
  4. # METADATA
  5. # title: Allow Ones
  6. allow {
  7. x == 1
  8. }
  9. # METADATA
  10. # title: Allow Twos
  11. allow {
  12. x == 2
  13. }

Title

The title annotation is a string value giving a human-readable name to the annotation target.

Example

  1. # METADATA
  2. # title: Allow Ones
  3. allow {
  4. x == 1
  5. }
  6. # title: Allow Twos
  7. allow {
  8. x == 2
  9. }

Description

The description annotation is a string value describing the annotation target, such as its purpose.

Example

  1. # METADATA
  2. # description: |
  3. # The 'allow' rule...
  4. # Is about allowing things.
  5. # Not denying them.
  6. ...
  7. }

When a related-resource entry is presented as an object, it has two fields:

  • ref: a URL pointing to the resource (required).
  • description: a text describing the resource.

When a related-resource entry is presented as a string, it needs to be a valid URL.

Examples

  1. # METADATA
  2. # related_resources:
  3. # - ref: https://example.com
  4. # ...
  5. # - ref: https://example.com/foo
  6. # description: A text describing this resource
  7. allow {
  8. ...
  9. }

Authors

The authors annotation is a list of author entries, where each entry denotes an author. An author entry can either be an object or a short-form string.

Object Author Format

When an author entry is presented as an object, it has two fields:

  • name: the name of the author
  • email: the email of the author

At least one of the above fields are required for a valid author entry.

String Author Format

When an author entry is presented as a string, it has the format { name } [ "<" email ">"]; where the name of the author is a sequence of whitespace-separated words. Optionally, the last word may represent an email, if enclosed with <>.

Examples

  1. # METADATA
  2. # authors:
  3. # - name: John Doe
  4. # ...
  5. # - name: Jane Doe
  6. # email: jane@example.com
  7. allow {
  8. ...
  9. }
  1. # METADATA
  2. # authors:
  3. # - John Doe
  4. # ...
  5. # - Jane Doe <jane@example.com>
  6. allow {
  7. ...
  8. }

Organizations

Example

  1. # METADATA
  2. # organizations:
  3. # - Acme Corp.
  4. # ...
  5. # - Tyrell Corp.
  6. allow {
  7. }

The schemas annotation is a list of key value pairs, associating schemas to data values. In-depth information on this topic can be found here.

Example

  1. # METADATA
  2. # schemas:
  3. # - input: schema.input
  4. # - data.acl: schema["acl-schema"]
  5. access := data.acl["alice"]
  6. access[_] == input.operation
  7. }

Custom

The custom annotation is a mapping of user-defined data, mapping string keys to arbitrarily typed values.

Example

Accessing annotations

Inspect command

Annotations can be listed through the inspect command by using the -a flag:

  1. opa inspect -a

The ast.AnnotationSet is a collection of all ast.Annotations declared in a set of modules. An ast.AnnotationSet can be created from a slice of compiled modules:

  1. var modules []*ast.Module
  2. ...
  3. as, err := ast.BuildAnnotationSet(modules)
  4. if err != nil {
  5. // Handle error.
  6. }

or can be retrieved from an ast.Compiler instance:

  1. var modules []*ast.Module
  2. ...
  3. compiler := ast.NewCompiler()
  4. compiler.Compile(modules)
  5. as := compiler.GetAnnotationSet()

The ast.AnnotationSet can be flattened into a slice of ast.AnnotationsRef, which is a complete, sorted list of all annotations, grouped by the path and location of their targeted package or -rule.

  1. flattened := as.Flatten()
  2. for _, entry := range flattened {
  3. fmt.Printf("%v at %v has annotations %v\n",
  4. entry.Path,
  5. entry.Location,
  6. entry.Annotations)
  7. }
  8. // Output:
  9. // data.foo at foo.rego:5 has annotations {"scope":"subpackages","organizations":["Acme Corp."]}
  10. // data.foo.bar at mod:3 has annotations {"scope":"package","description":"A couple of useful rules"}
  11. // data.foo.bar.p at mod:7 has annotations {"scope":"rule","title":"My Rule P"}
  12. //
  13. // For modules:
  14. // # METADATA
  15. // # scope: subpackages
  16. // # organizations:
  17. // # - Acme Corp.
  18. // package foo
  19. // ---
  20. // # METADATA
  21. // # description: A couple of useful rules
  22. // package foo.bar
  23. //
  24. // # METADATA
  25. // # title: My Rule P
  26. // p := 7