// Copyright 2016 The OPA Authors. All rights reserved. // Use of this source code is governed by an Apache2 // license that can be found in the LICENSE file. package ast import ( "strings" "github.com/open-policy-agent/opa/types" ) // Builtins is the registry of built-in functions supported by OPA. // Call RegisterBuiltin to add a new built-in. var Builtins []*Builtin // RegisterBuiltin adds a new built-in function to the registry. func RegisterBuiltin(b *Builtin) { Builtins = append(Builtins, b) BuiltinMap[b.Name] = b if len(b.Infix) > 0 { BuiltinMap[b.Infix] = b } } // DefaultBuiltins is the registry of built-in functions supported in OPA // by default. When adding a new built-in function to OPA, update this // list. var DefaultBuiltins = [...]*Builtin{ // Unification/equality ("=") Equality, // Assignment (":=") Assign, // Comparisons GreaterThan, GreaterThanEq, LessThan, LessThanEq, NotEqual, Equal, // Arithmetic Plus, Minus, Multiply, Divide, Round, Abs, Rem, // Bitwise Arithmetic BitsOr, BitsAnd, BitsNegate, BitsXOr, BitsShiftLeft, BitsShiftRight, // Binary And, Or, // Aggregates Count, Sum, Product, Max, Min, Any, All, // Arrays ArrayConcat, ArraySlice, // Conversions ToNumber, // Casts (DEPRECATED) CastObject, CastNull, CastBoolean, CastString, CastSet, CastArray, // Regular Expressions RegexMatch, RegexSplit, GlobsMatch, RegexTemplateMatch, RegexFind, RegexFindAllStringSubmatch, // Sets SetDiff, Intersection, Union, // Strings Concat, FormatInt, IndexOf, Substring, Lower, Upper, Contains, StartsWith, EndsWith, Split, Replace, ReplaceN, Trim, TrimLeft, TrimPrefix, TrimRight, TrimSuffix, TrimSpace, Sprintf, // Encoding JSONMarshal, JSONUnmarshal, Base64Encode, Base64Decode, Base64UrlEncode, Base64UrlDecode, URLQueryDecode, URLQueryEncode, URLQueryEncodeObject, YAMLMarshal, YAMLUnmarshal, // Object Manipulation ObjectUnion, ObjectRemove, ObjectFilter, ObjectGet, // JSON Object Manipulation JSONFilter, JSONRemove, // Tokens JWTDecode, JWTVerifyRS256, JWTVerifyPS256, JWTVerifyES256, JWTVerifyHS256, JWTDecodeVerify, JWTEncodeSignRaw, JWTEncodeSign, // Time NowNanos, ParseNanos, ParseRFC3339Nanos, ParseDurationNanos, Date, Clock, Weekday, // Crypto CryptoX509ParseCertificates, CryptoMd5, CryptoSha1, CryptoSha256, // Graphs WalkBuiltin, // Sort Sort, // Types IsNumber, IsString, IsBoolean, IsArray, IsSet, IsObject, IsNull, TypeNameBuiltin, // HTTP HTTPSend, // Rego RegoParseModule, // OPA OPARuntime, // Tracing Trace, // CIDR NetCIDROverlap, NetCIDRIntersects, NetCIDRContains, NetCIDRExpand, // Glob GlobMatch, GlobQuoteMeta, // Units UnitsParseBytes, } // BuiltinMap provides a convenient mapping of built-in names to // built-in definitions. var BuiltinMap map[string]*Builtin // IgnoreDuringPartialEval is a set of built-in functions that should not be // evaluated during partial evaluation. These functions are not partially // evaluated because they are not pure. var IgnoreDuringPartialEval = []*Builtin{ NowNanos, HTTPSend, } /** * Unification */ // Equality represents the "=" operator. var Equality = &Builtin{ Name: "eq", Infix: "=", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } /** * Assignment */ // Assign represents the assignment (":=") operator. var Assign = &Builtin{ Name: "assign", Infix: ":=", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } /** * Comparisons */ // GreaterThan represents the ">" comparison operator. var GreaterThan = &Builtin{ Name: "gt", Infix: ">", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } // GreaterThanEq represents the ">=" comparison operator. var GreaterThanEq = &Builtin{ Name: "gte", Infix: ">=", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } // LessThan represents the "<" comparison operator. var LessThan = &Builtin{ Name: "lt", Infix: "<", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } // LessThanEq represents the "<=" comparison operator. var LessThanEq = &Builtin{ Name: "lte", Infix: "<=", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } // NotEqual represents the "!=" comparison operator. var NotEqual = &Builtin{ Name: "neq", Infix: "!=", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } // Equal represents the "==" comparison operator. var Equal = &Builtin{ Name: "equal", Infix: "==", Decl: types.NewFunction( types.Args(types.A, types.A), types.B, ), } /** * Arithmetic */ // Plus adds two numbers together. var Plus = &Builtin{ Name: "plus", Infix: "+", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // Minus subtracts the second number from the first number or computes the diff // between two sets. var Minus = &Builtin{ Name: "minus", Infix: "-", Decl: types.NewFunction( types.Args( types.NewAny(types.N, types.NewSet(types.A)), types.NewAny(types.N, types.NewSet(types.A)), ), types.NewAny(types.N, types.NewSet(types.A)), ), } // Multiply multiplies two numbers together. var Multiply = &Builtin{ Name: "mul", Infix: "*", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // Divide divides the first number by the second number. var Divide = &Builtin{ Name: "div", Infix: "/", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // Round rounds the number up to the nearest integer. var Round = &Builtin{ Name: "round", Decl: types.NewFunction( types.Args(types.N), types.N, ), } // Abs returns the number without its sign. var Abs = &Builtin{ Name: "abs", Decl: types.NewFunction( types.Args(types.N), types.N, ), } // Rem returns the remainder for x%y for y != 0. var Rem = &Builtin{ Name: "rem", Infix: "%", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } /** * Bitwise */ // BitsOr returns the bitwise "or" of two integers. var BitsOr = &Builtin{ Name: "bits.or", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // BitsAnd returns the bitwise "and" of two integers. var BitsAnd = &Builtin{ Name: "bits.and", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // BitsNegate returns the bitwise "negation" of an integer (i.e. flips each // bit). var BitsNegate = &Builtin{ Name: "bits.negate", Decl: types.NewFunction( types.Args(types.N), types.N, ), } // BitsXOr returns the bitwise "exclusive-or" of two integers. var BitsXOr = &Builtin{ Name: "bits.xor", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // BitsShiftLeft returns a new integer with its bits shifted some value to the // left. var BitsShiftLeft = &Builtin{ Name: "bits.lsh", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } // BitsShiftRight returns a new integer with its bits shifted some value to the // right. var BitsShiftRight = &Builtin{ Name: "bits.rsh", Decl: types.NewFunction( types.Args(types.N, types.N), types.N, ), } /** * Sets */ // And performs an intersection operation on sets. var And = &Builtin{ Name: "and", Infix: "&", Decl: types.NewFunction( types.Args( types.NewSet(types.A), types.NewSet(types.A), ), types.NewSet(types.A), ), } // Or performs a union operation on sets. var Or = &Builtin{ Name: "or", Infix: "|", Decl: types.NewFunction( types.Args( types.NewSet(types.A), types.NewSet(types.A), ), types.NewSet(types.A), ), } /** * Aggregates */ // Count takes a collection or string and counts the number of elements in it. var Count = &Builtin{ Name: "count", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.A), types.NewArray(nil, types.A), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), types.S, ), ), types.N, ), } // Sum takes an array or set of numbers and sums them. var Sum = &Builtin{ Name: "sum", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.N), types.NewArray(nil, types.N), ), ), types.N, ), } // Product takes an array or set of numbers and multiplies them. var Product = &Builtin{ Name: "product", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.N), types.NewArray(nil, types.N), ), ), types.N, ), } // Max returns the maximum value in a collection. var Max = &Builtin{ Name: "max", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.A), types.NewArray(nil, types.A), ), ), types.A, ), } // Min returns the minimum value in a collection. var Min = &Builtin{ Name: "min", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.A), types.NewArray(nil, types.A), ), ), types.A, ), } // All takes a list and returns true if all of the items // are true. A collection of length 0 returns true. var All = &Builtin{ Name: "all", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.A), types.NewArray(nil, types.A), ), ), types.B, ), } // Any takes a collection and returns true if any of the items // is true. A collection of length 0 returns false. var Any = &Builtin{ Name: "any", Decl: types.NewFunction( types.Args( types.NewAny( types.NewSet(types.A), types.NewArray(nil, types.A), ), ), types.B, ), } /** * Arrays */ // ArrayConcat returns the result of concatenating two arrays together. var ArrayConcat = &Builtin{ Name: "array.concat", Decl: types.NewFunction( types.Args( types.NewArray(nil, types.A), types.NewArray(nil, types.A), ), types.NewArray(nil, types.A), ), } // ArraySlice returns a slice of a given array var ArraySlice = &Builtin{ Name: "array.slice", Decl: types.NewFunction( types.Args( types.NewArray(nil, types.A), types.NewNumber(), types.NewNumber(), ), types.NewArray(nil, types.A), ), } /** * Conversions */ // ToNumber takes a string, bool, or number value and converts it to a number. // Strings are converted to numbers using strconv.Atoi. // Boolean false is converted to 0 and boolean true is converted to 1. var ToNumber = &Builtin{ Name: "to_number", Decl: types.NewFunction( types.Args( types.NewAny( types.N, types.S, types.B, types.NewNull(), ), ), types.N, ), } /** * Regular Expressions */ // RegexMatch takes two strings and evaluates to true if the string in the second // position matches the pattern in the first position. var RegexMatch = &Builtin{ Name: "re_match", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // RegexFindAllStringSubmatch returns an array of all successive matches of the expression. // It takes two strings and a number, the pattern, the value and number of matches to // return, -1 means all matches. var RegexFindAllStringSubmatch = &Builtin{ Name: "regex.find_all_string_submatch_n", Decl: types.NewFunction( types.Args( types.S, types.S, types.N, ), types.NewArray(nil, types.NewArray(nil, types.S)), ), } // RegexTemplateMatch takes two strings and evaluates to true if the string in the second // position matches the pattern in the first position. var RegexTemplateMatch = &Builtin{ Name: "regex.template_match", Decl: types.NewFunction( types.Args( types.S, types.S, types.S, types.S, ), types.B, ), } // RegexSplit splits the input string by the occurrences of the given pattern. var RegexSplit = &Builtin{ Name: "regex.split", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.NewArray(nil, types.S), ), } // RegexFind takes two strings and a number, the pattern, the value and number of match values to // return, -1 means all match values. var RegexFind = &Builtin{ Name: "regex.find_n", Decl: types.NewFunction( types.Args( types.S, types.S, types.N, ), types.NewArray(nil, types.S), ), } // GlobsMatch takes two strings regexp-style strings and evaluates to true if their // intersection matches a non-empty set of non-empty strings. // Examples: // - "a.a." and ".b.b" -> true. // - "[a-z]*" and [0-9]+" -> not true. var GlobsMatch = &Builtin{ Name: "regex.globs_match", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } /** * Strings */ // Concat joins an array of strings with an input string. var Concat = &Builtin{ Name: "concat", Decl: types.NewFunction( types.Args( types.S, types.NewAny( types.NewSet(types.S), types.NewArray(nil, types.S), ), ), types.S, ), } // FormatInt returns the string representation of the number in the given base after converting it to an integer value. var FormatInt = &Builtin{ Name: "format_int", Decl: types.NewFunction( types.Args( types.N, types.N, ), types.S, ), } // IndexOf returns the index of a substring contained inside a string var IndexOf = &Builtin{ Name: "indexof", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.N, ), } // Substring returns the portion of a string for a given start index and a length. // If the length is less than zero, then substring returns the remainder of the string. var Substring = &Builtin{ Name: "substring", Decl: types.NewFunction( types.Args( types.S, types.N, types.N, ), types.S, ), } // Contains returns true if the search string is included in the base string var Contains = &Builtin{ Name: "contains", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // StartsWith returns true if the search string begins with the base string var StartsWith = &Builtin{ Name: "startswith", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // EndsWith returns true if the search string begins with the base string var EndsWith = &Builtin{ Name: "endswith", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // Lower returns the input string but with all characters in lower-case var Lower = &Builtin{ Name: "lower", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // Upper returns the input string but with all characters in upper-case var Upper = &Builtin{ Name: "upper", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // Split returns an array containing elements of the input string split on a delimiter. var Split = &Builtin{ Name: "split", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.NewArray(nil, types.S), ), } // Replace returns the given string with all instances of the second argument replaced // by the third. var Replace = &Builtin{ Name: "replace", Decl: types.NewFunction( types.Args( types.S, types.S, types.S, ), types.S, ), } // ReplaceN replaces a string from a list of old, new string pairs. // Replacements are performed in the order they appear in the target string, without overlapping matches. // The old string comparisons are done in argument order. var ReplaceN = &Builtin{ Name: "strings.replace_n", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty( types.S, types.S)), types.S, ), types.S, ), } // Trim returns the given string with all leading or trailing instances of the second // argument removed. var Trim = &Builtin{ Name: "trim", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.S, ), } // TrimLeft returns the given string with all leading instances of second argument removed. var TrimLeft = &Builtin{ Name: "trim_left", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.S, ), } // TrimPrefix returns the given string without the second argument prefix string. // If the given string doesn't start with prefix, it is returned unchanged. var TrimPrefix = &Builtin{ Name: "trim_prefix", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.S, ), } // TrimRight returns the given string with all trailing instances of second argument removed. var TrimRight = &Builtin{ Name: "trim_right", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.S, ), } // TrimSuffix returns the given string without the second argument suffix string. // If the given string doesn't end with suffix, it is returned unchanged. var TrimSuffix = &Builtin{ Name: "trim_suffix", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.S, ), } // TrimSpace return the given string with all leading and trailing white space removed. var TrimSpace = &Builtin{ Name: "trim_space", Decl: types.NewFunction( types.Args( types.S, ), types.S, ), } // Sprintf returns the given string, formatted. var Sprintf = &Builtin{ Name: "sprintf", Decl: types.NewFunction( types.Args( types.S, types.NewArray(nil, types.A), ), types.S, ), } // UnitsParseBytes converts strings like 10GB, 5K, 4mb, and the like into an // integer number of bytes. var UnitsParseBytes = &Builtin{ Name: "units.parse_bytes", Decl: types.NewFunction( types.Args( types.S, ), types.N, ), } /** * JSON */ // JSONMarshal serializes the input term. var JSONMarshal = &Builtin{ Name: "json.marshal", Decl: types.NewFunction( types.Args(types.A), types.S, ), } // JSONUnmarshal deserializes the input string. var JSONUnmarshal = &Builtin{ Name: "json.unmarshal", Decl: types.NewFunction( types.Args(types.S), types.A, ), } // JSONFilter filters the JSON object var JSONFilter = &Builtin{ Name: "json.filter", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty(types.A, types.A), ), types.NewAny( types.NewArray( nil, types.NewAny( types.S, types.NewArray( nil, types.A, ), ), ), types.NewSet( types.NewAny( types.S, types.NewArray( nil, types.A, ), ), ), ), ), types.A, ), } // JSONRemove removes paths in the JSON object var JSONRemove = &Builtin{ Name: "json.remove", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty(types.A, types.A), ), types.NewAny( types.NewArray( nil, types.NewAny( types.S, types.NewArray( nil, types.A, ), ), ), types.NewSet( types.NewAny( types.S, types.NewArray( nil, types.A, ), ), ), ), ), types.A, ), } // ObjectUnion creates a new object that is the asymmetric union of two objects var ObjectUnion = &Builtin{ Name: "object.union", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty(types.A, types.A), ), types.NewObject( nil, types.NewDynamicProperty(types.A, types.A), ), ), types.A, ), } // ObjectRemove Removes specified keys from an object var ObjectRemove = &Builtin{ Name: "object.remove", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty(types.A, types.A), ), types.NewAny( types.NewArray(nil, types.A), types.NewSet(types.A), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), ), ), types.A, ), } // ObjectFilter filters the object by keeping only specified keys var ObjectFilter = &Builtin{ Name: "object.filter", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty(types.A, types.A), ), types.NewAny( types.NewArray(nil, types.A), types.NewSet(types.A), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), ), ), types.A, ), } // Base64Encode serializes the input string into base64 encoding. var Base64Encode = &Builtin{ Name: "base64.encode", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // Base64Decode deserializes the base64 encoded input string. var Base64Decode = &Builtin{ Name: "base64.decode", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // Base64UrlEncode serializes the input string into base64url encoding. var Base64UrlEncode = &Builtin{ Name: "base64url.encode", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // Base64UrlDecode deserializes the base64url encoded input string. var Base64UrlDecode = &Builtin{ Name: "base64url.decode", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // URLQueryDecode decodes a URL encoded input string. var URLQueryDecode = &Builtin{ Name: "urlquery.decode", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // URLQueryEncode encodes the input string into a URL encoded string. var URLQueryEncode = &Builtin{ Name: "urlquery.encode", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // URLQueryEncodeObject encodes the given JSON into a URL encoded query string. var URLQueryEncodeObject = &Builtin{ Name: "urlquery.encode_object", Decl: types.NewFunction( types.Args( types.NewObject( nil, types.NewDynamicProperty( types.S, types.NewAny( types.S, types.NewArray(nil, types.S), types.NewSet(types.S))))), types.S, ), } // YAMLMarshal serializes the input term. var YAMLMarshal = &Builtin{ Name: "yaml.marshal", Decl: types.NewFunction( types.Args(types.A), types.S, ), } // YAMLUnmarshal deserializes the input string. var YAMLUnmarshal = &Builtin{ Name: "yaml.unmarshal", Decl: types.NewFunction( types.Args(types.S), types.A, ), } /** * Tokens */ // JWTDecode decodes a JSON Web Token and outputs it as an Object. var JWTDecode = &Builtin{ Name: "io.jwt.decode", Decl: types.NewFunction( types.Args(types.S), types.NewArray([]types.Type{ types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), types.S, }, nil), ), } // JWTVerifyRS256 verifies if a RS256 JWT signature is valid or not. var JWTVerifyRS256 = &Builtin{ Name: "io.jwt.verify_rs256", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // JWTVerifyPS256 verifies if a PS256 JWT signature is valid or not. var JWTVerifyPS256 = &Builtin{ Name: "io.jwt.verify_ps256", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // JWTVerifyES256 verifies if a ES256 JWT signature is valid or not. var JWTVerifyES256 = &Builtin{ Name: "io.jwt.verify_es256", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // JWTVerifyHS256 verifies if a HS256 (secret) JWT signature is valid or not. var JWTVerifyHS256 = &Builtin{ Name: "io.jwt.verify_hs256", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // JWTDecodeVerify verifies a JWT signature under parameterized constraints and decodes the claims if it is valid. var JWTDecodeVerify = &Builtin{ Name: "io.jwt.decode_verify", Decl: types.NewFunction( types.Args( types.S, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), ), types.NewArray([]types.Type{ types.B, types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), }, nil), ), } // JWTEncodeSignRaw encodes and optionally sign a JSON Web Token. // Inputs are protected headers, payload, secret var JWTEncodeSignRaw = &Builtin{ Name: "io.jwt.encode_sign_raw", Decl: types.NewFunction( types.Args( types.S, types.S, types.S, ), types.S, ), } // JWTEncodeSign encodes and optionally sign a JSON Web Token. // Inputs are protected headers, payload, secret var JWTEncodeSign = &Builtin{ Name: "io.jwt.encode_sign", Decl: types.NewFunction( types.Args( types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), ), types.S, ), } /** * Time */ // NowNanos returns the current time since epoch in nanoseconds. var NowNanos = &Builtin{ Name: "time.now_ns", Decl: types.NewFunction( nil, types.N, ), } // ParseNanos returns the time in nanoseconds parsed from the string in the given format. var ParseNanos = &Builtin{ Name: "time.parse_ns", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.N, ), } // ParseRFC3339Nanos returns the time in nanoseconds parsed from the string in RFC3339 format. var ParseRFC3339Nanos = &Builtin{ Name: "time.parse_rfc3339_ns", Decl: types.NewFunction( types.Args(types.S), types.N, ), } // ParseDurationNanos returns the duration in nanoseconds represented by a duration string. // Duration string is similar to the Go time.ParseDuration string var ParseDurationNanos = &Builtin{ Name: "time.parse_duration_ns", Decl: types.NewFunction( types.Args(types.S), types.N, ), } // Date returns the [year, month, day] for the nanoseconds since epoch. var Date = &Builtin{ Name: "time.date", Decl: types.NewFunction( types.Args( types.NewAny( types.N, types.NewArray([]types.Type{types.N, types.S}, nil), ), ), types.NewArray([]types.Type{types.N, types.N, types.N}, nil), ), } // Clock returns the [hour, minute, second] of the day for the nanoseconds since epoch. var Clock = &Builtin{ Name: "time.clock", Decl: types.NewFunction( types.Args( types.NewAny( types.N, types.NewArray([]types.Type{types.N, types.S}, nil), ), ), types.NewArray([]types.Type{types.N, types.N, types.N}, nil), ), } // Weekday returns the day of the week (Monday, Tuesday, ...) for the nanoseconds since epoch. var Weekday = &Builtin{ Name: "time.weekday", Decl: types.NewFunction( types.Args( types.NewAny( types.N, types.NewArray([]types.Type{types.N, types.S}, nil), ), ), types.S, ), } /** * Crypto. */ // CryptoX509ParseCertificates returns one or more certificates from the given // base64 encoded string containing DER encoded certificates that have been // concatenated. var CryptoX509ParseCertificates = &Builtin{ Name: "crypto.x509.parse_certificates", Decl: types.NewFunction( types.Args(types.S), types.NewArray(nil, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A))), ), } // CryptoMd5 returns a string representing the input string hashed with the md5 function var CryptoMd5 = &Builtin{ Name: "crypto.md5", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // CryptoSha1 returns a string representing the input string hashed with the sha1 function var CryptoSha1 = &Builtin{ Name: "crypto.sha1", Decl: types.NewFunction( types.Args(types.S), types.S, ), } // CryptoSha256 returns a string representing the input string hashed with the sha256 function var CryptoSha256 = &Builtin{ Name: "crypto.sha256", Decl: types.NewFunction( types.Args(types.S), types.S, ), } /** * Graphs. */ // WalkBuiltin generates [path, value] tuples for all nested documents // (recursively). var WalkBuiltin = &Builtin{ Name: "walk", Relation: true, Decl: types.NewFunction( types.Args(types.A), types.NewArray( []types.Type{ types.NewArray(nil, types.A), types.A, }, nil, ), ), } /** * Sorting */ // Sort returns a sorted array. var Sort = &Builtin{ Name: "sort", Decl: types.NewFunction( types.Args( types.NewAny( types.NewArray(nil, types.A), types.NewSet(types.A), ), ), types.NewArray(nil, types.A), ), } /** * Type */ // IsNumber returns true if the input value is a number var IsNumber = &Builtin{ Name: "is_number", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } // IsString returns true if the input value is a string. var IsString = &Builtin{ Name: "is_string", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } // IsBoolean returns true if the input value is a boolean. var IsBoolean = &Builtin{ Name: "is_boolean", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } // IsArray returns true if the input value is an array. var IsArray = &Builtin{ Name: "is_array", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } // IsSet returns true if the input value is a set. var IsSet = &Builtin{ Name: "is_set", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } // IsObject returns true if the input value is an object. var IsObject = &Builtin{ Name: "is_object", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } // IsNull returns true if the input value is null. var IsNull = &Builtin{ Name: "is_null", Decl: types.NewFunction( types.Args( types.A, ), types.B, ), } /** * Type Name */ // TypeNameBuiltin returns the type of the input. var TypeNameBuiltin = &Builtin{ Name: "type_name", Decl: types.NewFunction( types.Args( types.NewAny( types.A, ), ), types.S, ), } /** * HTTP Request */ // HTTPSend returns a HTTP response to the given HTTP request. var HTTPSend = &Builtin{ Name: "http.send", Decl: types.NewFunction( types.Args( types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), ), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), ), } /** * Rego */ // RegoParseModule parses the input Rego file and returns a JSON representation // of the AST. var RegoParseModule = &Builtin{ Name: "rego.parse_module", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), // TODO(tsandall): import AST schema ), } /** * OPA */ // OPARuntime returns an object containing OPA runtime information such as the // configuration that OPA was booted with. var OPARuntime = &Builtin{ Name: "opa.runtime", Decl: types.NewFunction( nil, types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)), ), } /** * Trace */ // Trace prints a note that is included in the query explanation. var Trace = &Builtin{ Name: "trace", Decl: types.NewFunction( types.Args( types.S, ), types.B, ), } /** * Set */ // Intersection returns the intersection of the given input sets var Intersection = &Builtin{ Name: "intersection", Decl: types.NewFunction( types.Args( types.NewSet(types.NewSet(types.A)), ), types.NewSet(types.A), ), } // Union returns the union of the given input sets var Union = &Builtin{ Name: "union", Decl: types.NewFunction( types.Args( types.NewSet(types.NewSet(types.A)), ), types.NewSet(types.A), ), } /** * Glob */ // GlobMatch - not to be confused with regex.globs_match - parses and matches strings against the glob notation. var GlobMatch = &Builtin{ Name: "glob.match", Decl: types.NewFunction( types.Args( types.S, types.NewArray(nil, types.S), types.S, ), types.B, ), } // GlobQuoteMeta returns a string which represents a version of the pattern where all asterisks have been escaped. var GlobQuoteMeta = &Builtin{ Name: "glob.quote_meta", Decl: types.NewFunction( types.Args( types.S, ), types.S, ), } /** * Net CIDR */ // NetCIDRIntersects checks if a cidr intersects with another cidr and returns true or false var NetCIDRIntersects = &Builtin{ Name: "net.cidr_intersects", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // NetCIDRExpand returns a set of hosts inside the specified cidr. var NetCIDRExpand = &Builtin{ Name: "net.cidr_expand", Decl: types.NewFunction( types.Args( types.S, ), types.NewSet(types.S), ), } // NetCIDRContains checks if a cidr or ip is contained within another cidr and returns true or false var NetCIDRContains = &Builtin{ Name: "net.cidr_contains", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } /** * Deprecated built-ins. */ // SetDiff has been replaced by the minus built-in. var SetDiff = &Builtin{ Name: "set_diff", Decl: types.NewFunction( types.Args( types.NewSet(types.A), types.NewSet(types.A), ), types.NewSet(types.A), ), } // NetCIDROverlap has been replaced by the `net.cidr_contains` built-in. var NetCIDROverlap = &Builtin{ Name: "net.cidr_overlap", Decl: types.NewFunction( types.Args( types.S, types.S, ), types.B, ), } // CastArray checks the underlying type of the input. If it is array or set, an array // containing the values is returned. If it is not an array, an error is thrown. var CastArray = &Builtin{ Name: "cast_array", Decl: types.NewFunction( types.Args(types.A), types.NewArray(nil, types.A), ), } // CastSet checks the underlying type of the input. // If it is a set, the set is returned. // If it is an array, the array is returned in set form (all duplicates removed) // If neither, an error is thrown var CastSet = &Builtin{ Name: "cast_set", Decl: types.NewFunction( types.Args(types.A), types.NewSet(types.A), ), } // CastString returns input if it is a string; if not returns error. // For formatting variables, see sprintf var CastString = &Builtin{ Name: "cast_string", Decl: types.NewFunction( types.Args(types.A), types.S, ), } // CastBoolean returns input if it is a boolean; if not returns error. var CastBoolean = &Builtin{ Name: "cast_boolean", Decl: types.NewFunction( types.Args(types.A), types.B, ), } // CastNull returns null if input is null; if not returns error. var CastNull = &Builtin{ Name: "cast_null", Decl: types.NewFunction( types.Args(types.A), types.NewNull(), ), } // CastObject returns the given object if it is null; throws an error otherwise var CastObject = &Builtin{ Name: "cast_object", Decl: types.NewFunction( types.Args(types.A), types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), ), } // ObjectGet returns takes an object and returns a value under its key if // present, otherwise it returns the default. var ObjectGet = &Builtin{ Name: "object.get", Decl: types.NewFunction( types.Args( types.NewObject(nil, types.NewDynamicProperty(types.A, types.A)), types.A, types.A, ), types.A, ), } // Builtin represents a built-in function supported by OPA. Every built-in // function is uniquely identified by a name. type Builtin struct { Name string // Unique name of built-in function, e.g., (arg1,arg2,...,argN) Infix string // Unique name of infix operator. Default should be unset. Decl *types.Function // Built-in function type declaration. Relation bool // Indicates if the built-in acts as a relation. } // Expr creates a new expression for the built-in with the given operands. func (b *Builtin) Expr(operands ...*Term) *Expr { ts := make([]*Term, len(operands)+1) ts[0] = NewTerm(b.Ref()) for i := range operands { ts[i+1] = operands[i] } return &Expr{ Terms: ts, } } // Call creates a new term for the built-in with the given operands. func (b *Builtin) Call(operands ...*Term) *Term { call := make(Call, len(operands)+1) call[0] = NewTerm(b.Ref()) for i := range operands { call[i+1] = operands[i] } return NewTerm(call) } // Ref returns a Ref that refers to the built-in function. func (b *Builtin) Ref() Ref { parts := strings.Split(b.Name, ".") ref := make(Ref, len(parts)) ref[0] = VarTerm(parts[0]) for i := 1; i < len(parts); i++ { ref[i] = StringTerm(parts[i]) } return ref } // IsTargetPos returns true if a variable in the i-th position will be bound by // evaluating the call expression. func (b *Builtin) IsTargetPos(i int) bool { return len(b.Decl.Args()) == i } func init() { BuiltinMap = map[string]*Builtin{} for _, b := range DefaultBuiltins { RegisterBuiltin(b) } }