diff options
| author | mo khan <mo@mokhan.ca> | 2025-05-02 14:29:41 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-05-02 14:29:41 -0600 |
| commit | c583bcd1473205104a1e1af812ed4976d30c7baa (patch) | |
| tree | 933edf78a4ac8aea55256e42641e56bbb4c58834 | |
| parent | 91defaefca47e9cebbe92c6abf33c4423df9bc7d (diff) | |
refactor: remove anything unrelated to the authz daemon
65 files changed, 191 insertions, 4772 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 449564fa..d2a608fd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,16 +1,35 @@ -test: - image: debian:bookworm +stages: + - build + - test + - validate + - runway_staging + - runway_production + +variables: + CONTAINER_IMAGE_COMMIT: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA + +include: + - project: 'gitlab-com/gl-infra/platform/runway/runwayctl' + file: 'ci-tasks/service-project/runway.yml' + inputs: + runway_service_id: authzd + image: "$CONTAINER_IMAGE_COMMIT" + runway_version: v3.61.5 + +build image: + image: docker:28 + interruptible: true + stage: build + services: + - docker:28-dind + before_script: + - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY script: - - apt-get update -y - - apt-get install -y build-essential chromium firefox-esr curl libffi-dev zlib1g-dev libyaml-dev - - curl https://mise.run | sh - - ~/.local/bin/mise install - - echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc - - source ~/.bashrc - - echo '127.0.0.1 api.example.com' >> /etc/hosts - - echo '127.0.0.1 idp.example.com' >> /etc/hosts - - echo '127.0.0.1 ui.example.com' >> /etc/hosts - - gem update --system - - gem install bundler - - make - - ruby ./script/cibuild + - docker build --tag $CONTAINER_IMAGE_COMMIT . + - docker push $CONTAINER_IMAGE_COMMIT + +unit: + image: golang:alpine + stage: test + script: + - go test ./... diff --git a/.tool-versions b/.tool-versions index b141417e..eb4df2a3 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,5 +1,5 @@ cargo latest golang 1.24.0 +make 4.4.1 protoc 3.19.6 -ruby 3.4.2 rust stable diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..d4e2b99d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +# syntax=docker/dockerfile:1 +FROM golang:1.24.0 AS build +ENV CGO_ENABLED=0 +WORKDIR /app +COPY . ./ +RUN go build -o authzd ./cmd/authzd/main.go && mv ./authzd /bin/authzd + + +FROM scratch +ENV BIND_ADDR=":http" +EXPOSE 80 +WORKDIR /var/www/ +COPY --from=build /bin/authzd /bin/authzd +CMD ["/bin/authzd"] @@ -12,14 +12,3 @@ install-tools: @command -v protoc-gen-go @command -v protoc-gen-go-grpc @command -v protoc-gen-twirp_ruby - @command -v step - @command -v step-ca - -clean: - @rm -f slides.pdf - -slides.pdf: clean - @pandoc -t beamer -V fontsize=8pt -s doc/share/authz/SLIDES.md -o slides.pdf - -presentation: slides.pdf - @xdg-open slides.pdf @@ -1,13 +1,7 @@ -# Authx - Proof of Concept +# authzd - Authorization Daemon -This repository explores various authentication and authorization workflows by introducing a separate authn/authz service. -It serves as a proof of concept to illustrate potential workflows, not a production ready implementation. - -To keep the implementation accessible, external dependencies have been minimized, ensuring a clear reference for understanding key concepts, including: - -* SAML based authentication including IdP chaining to external identity providers -* OIDC based authentication -* OAuth endpoints with links to relevant RFCs for proper usage guidance +This repository host a minimal PDP service used for making authorization +decisions via a gRPC endpoint. ## Architecture @@ -17,84 +11,57 @@ To keep the implementation accessible, external dependencies have been minimized ------------- | V -----|:8080|----------------------------------------------- +----|:443|------------------------------------------------------------- | V - --------------- - | API Gateway | (use casbin to evict early, reverse proxy, inject context headers) - --------------- - | - | -------------------- - |--->| IdP (saml, oidc) | - | -------------------- - | | :http | :grpc | (use declarative_policy) - | -------------------- - | A A - ----------- | | - | | | | - V V | | - ------ ------------ | - | UI | | REST API |----| - ------ ------------ - -[UI]: ui.example.com -[REST API]: api.example.com -[IdP]: idp.example.com + | ---------------------------------------- + | | ______________________ | + |-->(:443)| envoy ->(:80)| /var/run/sparkled | | + | | ---------------------- | + | ---------------------------------------- + | + | ------------------- + | | IdP / IAM | + | |-------- | + |--->| :http | |---- pub membership change ---| + | |-------- | | + | ------------------- | + | ( nats.io) + | | + | |---- sub membership change --- + | | + | V (update acls) + | ------------------------------------- + | | ___________________ | + |-->(:443)| envoy ->(:80)| /var/run/authzd | | + | ------------------| | + ------------------------------------- + | + |----> cron reconciliation process >---->-------| + A | + |- audit, validate list, notify, remediate --| ``` -I have ommitted TLS, RS256 from the prototype to offload the decision of key -management and rotation. See [smallstep](https://smallstep.com/docs/step-cli/) -for PKI management. - -CSV files are used instead of a database to simulate different types of -scenarios. The following organizational hierarchy is demonstrated here: +## Getting Started -``` -Organization(name: "default") - * Group(name: "A") - * Project(name: "A1") - * Group(name: "B") - * Project(name: "B1") -Organization(name: "gitlab") - * Group(name: "gitlab-org") - * Project(name: "gitlab") - * Group(name: "gitlab-com") - * Group(name: "gl-security") - * Group(name: "test-projects") - * Project(name: "eicar-test-project") - * Project(name: "disclosures") - * Group(name: "support") - * Group(name: "toolbox") - * Project(name: "changelog-parser") - * Project(name: "handbook") - * Project(name: "www-gitlab-com") -``` +### Prerequisites -## Getting Started +- [mise](https://mise.jdx.dev/) +- [make](https://www.gnu.org/software/make/) 1. Install tools: ```sh $ mise install - ``` - -1. Add entries to `/etc/hosts`: - - ```sh - $ tail -n3 /etc/hosts - 127.0.0.1 api.example.com - 127.0.0.1 idp.example.com - 127.0.0.1 ui.example.com + $ make install-tools ``` 1. Start servers: ```sh - $ mage + $ mage servers ``` -1. Open a browser to `http://ui.example.com:8080/`. - ## Questions See the [FAQ][9] @@ -106,9 +73,7 @@ See the [FAQ][9] * [protocol buffers][7] * [twirp][8] -[2]: https://gitlab.com/gitlab-org/gitlab/-/tree/master/app/policies [5]: https://tip.golang.org/doc/modules/managing-dependencies#tools [6]: https://grpc.io/docs/ [7]: https://protobuf.dev/programming-guides/proto3/ [8]: https://github.com/arthurnn/twirp-ruby/wiki/Code-Generation -[9]: ./doc/share/authz/FAQ.md diff --git a/bin/api b/bin/api deleted file mode 100755 index 180aa874..00000000 --- a/bin/api +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env ruby - -require 'bundler/inline' - -gemfile do - source 'https://rubygems.org' - - gem "csv", "~> 3.0" - gem "declarative_policy", "~> 1.0" - gem "erb", "~> 4.0" - gem "globalid", "~> 1.0" - gem "google-protobuf", "~> 3.0" - gem "json", "~> 2.0" - gem "logger", "~> 1.0" - gem "rack", "~> 3.0" - gem "rackup", "~> 2.0" - gem "securerandom", "~> 0.1" - gem "twirp", "~> 1.0" - gem "webrick", "~> 1.0" -end - -lib_path = Pathname.new(__FILE__).parent.parent.join('lib').realpath.to_s -$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path) - -require 'authx/rpc' - -$scheme = ENV.fetch("SCHEME", "http") -$port = ENV.fetch("PORT", 8284).to_i -$host = ENV.fetch("HOST", "localhost:#{$port}") - -class Entity - class << self - def all - @items ||= ::CSV.read(File.join(__dir__, "../db/api/#{self.name.downcase}s.csv"), headers: true).map do |row| - new(row.to_h.transform_keys(&:to_sym)) - end - end - - def create!(attributes) - new({ id: SecureRandom.uuid }.merge(attributes)).tap do |item| - all << item - end - end - end - - def initialize(attributes = {}) - @attributes = attributes - end - - def id - self[:id] - end - - def [](attribute) - @attributes.fetch(attribute.to_sym) - end - - def to_h - @attributes - end - - def to_gid - ::GlobalID.create(self, app: "example") - end -end - -class Organization < Entity - class << self - def default - @default ||= all.find { |organization| organization[:name] == "default" } - end - end -end - -class Group < Entity -end - -class Project < Entity -end - -module HTTPHelpers - def authorized?(request, permission, resource) - raise [permission, resource].inspect if resource.nil? - authorization = Rack::Auth::AbstractRequest.new(request.env) - return false unless authorization.provided? - - response = rpc.allowed({ - subject: authorization.params, - permission: permission, - resource: resource.to_gid.to_s, - }, headers: { 'Authorization' => "Bearer #{authorization.params}"}) - puts [response&.data&.result, permission, resource.to_gid.to_s].inspect - response.error.nil? && response.data.result - end - - def json_not_found - http_response(code: 404) - end - - def json_ok(body) - http_response(code: 200, body: JSON.pretty_generate(body)) - end - - def json_created(body) - http_response(code: 201, body: JSON.pretty_generate(body.to_h)) - end - - def json_unauthorized(permission, resource) - http_response(code: 401, body: JSON.pretty_generate({ - error: { - code: 401, - message: "`#{permission}` is required on `#{resource.to_gid}`", - } - })) - end - - def http_response(code:, headers: { 'Content-Type' => 'application/json' }, body: nil) - [ - code, - headers.merge({ 'X-Backend-Server' => 'REST' }), - [body].compact - ] - end -end - -class API - include HTTPHelpers - - attr_reader :rpc - - def initialize - @rpc = ::Authx::Rpc::AbilityClient.new("http://idp.example.com:8080/twirp") - end - - def call(env) - request = Rack::Request.new(env) - case request.request_method - when Rack::GET - case request.path - when "/organizations", "/organizations.json" - return json_ok(Organization.all.map(&:to_h)) - when "/groups", "/groups.json" - resource = Organization.default - if authorized?(request, :read_group, resource) - return json_ok(Group.all.map(&:to_h)) - else - return json_unauthorized(:read_group, resource) - end - when "/projects", "/projects.json" - resource = Organization.default - if authorized?(request, :read_project, resource) - return json_ok(Project.all.map(&:to_h)) - else - return json_unauthorized(:read_project, resource) - end - end - when Rack::POST - case request.path - when "/projects", "/projects.json" - resource = Organization.default - if authorized?(request, :create_project, resource) - return json_created(Project.create!(JSON.parse(request.body.read, symbolize_names: true))) - else - return json_unauthorized(:create_project, resource) - end - end - end - json_not_found - end - - private -end - -if __FILE__ == $0 - app = Rack::Builder.new do - use Rack::CommonLogger - use Rack::Reloader - run API.new - end.to_app - - Rackup::Server.start(app: app, Port: $port) -end diff --git a/bin/idp b/bin/idp deleted file mode 100755 index 62462deb..00000000 --- a/bin/idp +++ /dev/null @@ -1,895 +0,0 @@ -#!/usr/bin/env ruby - -require "bundler/inline" - -gemfile do - source "https://rubygems.org" - - gem "base64", "~> 0.1" - gem "bcrypt", "~> 3.0" - gem "csv", "~> 3.0" - gem "declarative_policy", "~> 1.0" - gem "erb", "~> 4.0" - gem "globalid", "~> 1.0" - gem "google-protobuf", "~> 3.0" - gem "rack", "~> 3.0" - gem "rack-session", "~> 2.0" - gem "rackup", "~> 2.0" - gem "saml-kit", "1.4.0" - gem "twirp", "~> 1.0" - gem "warden", "~> 1.0" - gem "webrick", "~> 1.0" -end - -lib_path = Pathname.new(__FILE__).parent.parent.join('lib').realpath.to_s -$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path) - -require 'authx/rpc' - -$scheme = ENV.fetch("SCHEME", "http") -$port = ENV.fetch("PORT", 8282).to_i -$host = ENV.fetch("HOST", "localhost:#{$port}") - -DeclarativePolicy.configure do - name_transformation do |name| - "::Authz::#{name}Policy" - end -end - -Warden::Manager.serialize_into_session do |user| - user.id -end - -Warden::Manager.serialize_from_session do |id| - ::Authn::User.find(id) -end - -Warden::Strategies.add(:password) do - def valid? - params['username'] && params['password'] - end - - def authenticate! - user = ::Authn::User.login(params.transform_keys(&:to_sym)) - user.nil? ? fail!("Could not log in") : success!(user) - end -end - -module HTTPHelpers - def current_user?(request) - request.env['warden'].authenticated? - end - - def current_user(request) - request.env['warden'].user - end - - def default_headers - { - 'X-Powered-By' => 'IdP' - } - end - - def http_not_found - [404, default_headers, []] - end - - def http_ok(headers = {}, body = nil) - [200, default_headers.merge(headers), [body]] - end - - def http_redirect_to(location) - [302, { 'Location' => "#{$scheme}://#{$host}#{location}" }, []] - end -end - -module Authn - class User - include ::BCrypt - - class << self - def all - @all ||= ::CSV.read(File.join(__dir__, "../db/idp/users.csv"), headers: true).map do |row| - new(row.to_h.transform_keys(&:to_sym)) - end - end - - def find(id) - all.find do |user| - user[:id] == id - end - end - - def find_by - all.find do |user| - yield user - end - end - - def find_by_email(email) - find_by do |user| - user[:email] == email - end - end - - def find_by_username(username) - find_by do |user| - user[:username] == username - end - end - - def login(params = {}) - user = find_by_username(params[:username]) - user&.valid_password?(params[:password]) ? user : nil - end - end - - attr_reader :id - - def initialize(attributes) - @attributes = attributes - @id = self[:id] - end - - def [](attribute) - @attributes.fetch(attribute.to_sym) - end - - def name_id_for(name_id_format) - if name_id_format == Saml::Kit::Namespaces::EMAIL_ADDRESS - self[:email] - else - self[:id] - end - end - - def create_access_token - ::Authz::JWT.new( - sub: to_global_id.to_s, - auth_time: Time.now.to_i, - email: self[:email], - username: self[:username], - ) - end - - def create_id_token - ::Authz::JWT.new(sub: to_global_id.to_s) - end - - def assertion_attributes_for(request) - { - email: self[:email], - } - end - - def valid_password?(entered_password) - ::BCrypt::Password.new(self[:password_digest]) == entered_password - end - - def to_global_id - ::GlobalID.new( - ::URI::GID.build( - app: "example", - model_name: "User", - model_id: id, - params: {} - ) - ).to_s - end - end - - class OnDemandRegistry < Saml::Kit::DefaultRegistry - def metadata_for(entity_id) - found = super(entity_id) - return found if found - - register_url(entity_id, verify_ssl: false) - super(entity_id) - end - end - - class SessionsController - include ::HTTPHelpers - - def call(env) - request = Rack::Request.new(env) - case request.request_method - when Rack::GET - case request.path - when '/sessions/new' - return get_login(request) - end - when Rack::POST - case request.path - when '/sessions' - if (user = env['warden'].authenticate(:password)) - path = request.params["redirect_back"] ? request.params["redirect_back"] : "/" - return http_redirect_to(path) - else - return http_redirect_to("/sessions/new") - end - when '/sessions/delete' - request.env['warden'].logout - return http_redirect_to('/') - end - end - - http_not_found - end - - private - - def get_login(request) - template = <<~ERB - <!doctype html> - <html lang="en" data-theme="light"> - <head> - <title>IdP</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="color-scheme" content="light dark"> - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> - </head> - <body> - <main class="container"> - <nav> - <ul> - <li><strong>IdP</strong></li> - <li><a href="http://ui.example.com:8080/">UI</a></li> - </ul> - </nav> - - <form id="login-form" action="/sessions" method="post"> - <fieldset> - <label> - Username - <input type="input" placeholder="Username" id="username" name="username" value="" /> - </label> - <label> - Password - <input type="password" placeholder="Password" id="password" name="password" value="" /> - </label> - </fieldset> - - <input type="hidden" name="redirect_back" value="<%= request.params["redirect_back"] %>" /> - <input type="submit" id="login-button" value="Login" /> - </form> - </main> - </body> - </html> - ERB - html = ERB.new(template, trim_mode: '-').result(binding) - [200, { 'Content-Type' => "text/html" }, [html]] - end - end - - class SAMLController - include ::HTTPHelpers - - def initialize(scheme, host) - Saml::Kit.configure do |x| - x.entity_id = "#{$scheme}://#{$host}/saml/metadata.xml" - x.registry = OnDemandRegistry.new - x.logger = Logger.new("/dev/stderr") - end - - @saml_metadata = Saml::Kit::Metadata.build do |builder| - builder.contact_email = 'hi@example.com' - builder.organization_name = "Acme, Inc" - builder.organization_url = "#{scheme}://#{host}" - builder.build_identity_provider do |x| - x.add_single_sign_on_service("#{scheme}://#{host}/saml/new", binding: :http_post) - x.name_id_formats = [Saml::Kit::Namespaces::PERSISTENT, Saml::Kit::Namespaces::EMAIL_ADDRESS] - x.attributes << :email - end - end - end - - def call(env) - request = Rack::Request.new(env) - case request.request_method - when Rack::GET - case request.path - when "/saml/continue" - if current_user?(request) - saml_params = request.session[:saml_params] - return saml_post_back(request, current_user(request), saml_params) - else - return http_redirect_to("/sessions/new?redirect_back=/saml/continue") - end - when "/saml/metadata.xml" - return http_ok( - { 'Content-Type' => "application/samlmetadata+xml" }, - saml_metadata.to_xml(pretty: true) - ) - end - when Rack::POST - case request.path - when "/saml/new" - saml_params = saml_params_from(request) - - if current_user?(request) - return saml_post_back(request, current_user(request), saml_params) - else - request.session[:saml_params] = saml_params - return http_redirect_to("/sessions/new?redirect_back=/saml/continue") - end - end - end - - http_not_found - end - - private - - attr_reader :saml_metadata - - def saml_post_back(request, user, saml_params) - saml_request = binding_for(request).deserialize(saml_params) - - @builder = nil - url, saml_params = saml_request.response_for( - user, - binding: :http_post, - relay_state: saml_params[:RelayState] - ) { |builder| @builder = builder } - template = <<~ERB - <!doctype html> - <html lang="en" data-theme="light"> - <head> - <title>IdP</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="color-scheme" content="light dark"> - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> - </head> - <body> - <main class="container"> - <nav> - <ul> - <li><strong>IdP</strong></li> - <li><a href="http://ui.example.com:8080/">UI</a></li> - </ul> - </nav> - - <h2>Recieved SAML Request</h2> - <textarea readonly="readonly" disabled="disabled" cols=225 rows=8><%=- saml_request.to_xml(pretty: true) -%></textarea> - - <h2>Sending SAML Response (IdP -> SP)</h2> - <textarea readonly="readonly" disabled="disabled" cols=225 rows=32><%=- @builder.build.to_xml(pretty: true) -%></textarea> - <form id="postback-form" action="<%= url %>" method="post"> - <%- saml_params.each do |(key, value)| -%> - <input type="hidden" name="<%= key %>" value="<%= value %>" /> - <%- end -%> - <input id="submit-button" type="submit" value="Continue" /> - </form> - </main> - </body> - </html> - ERB - erb = ERB.new(template, trim_mode: '-') - html = erb.result(binding) - [200, { 'Content-Type' => "text/html" }, [html]] - end - - def saml_params_from(request) - if request.post? - { - "SAMLRequest" => request.params["SAMLRequest"], - "RelayState" => request.params["RelayState"], - } - else - query_string = request.query_string - on = query_string.include?("&") ? "&" : "&" - Hash[query_string.split(on).map { |x| x.split("=", 2) }].symbolize_keys - end - end - - def binding_for(request) - Saml::Kit::Bindings::HttpPost.new(location: "#{$scheme}://#{$host}/saml/new") - end - end -end - -class Organization - class << self - def find(id) - new - end - end -end - -module Authz - class OrganizationPolicy < DeclarativePolicy::Base - condition(:owner) { true } - - rule { owner }.enable :read_project - rule { owner }.enable :read_group - rule { owner }.enable :create_project - end - - class JWT - class << self - # TODO:: validate signature - def decode(encoded) - _header, body, _signature = encoded - .split('.', 3) - .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) rescue {} } - new(body) - end - end - - attr_reader :claims - - def initialize(claims) - now = Time.now.to_i - @claims = { - iss: "#{$scheme}://#{$host}", - iat: now, - aud: "", - nbf: now, - jti: SecureRandom.uuid, - exp: now + 3600, - }.merge(claims) - end - - def [](claim) - claims.fetch(claim) - end - - def active? - now = Time.now.to_i - self[:nbf] <= now && now < self[:exp] - end - - def to_jwt - [ - Base64.strict_encode64(JSON.generate(alg: "none")), - Base64.strict_encode64(JSON.generate(claims)), - "" - ].join(".") - end - end - - module Rpc - class Ability - def allowed(request, env) - { - result: can?(request) - } - end - - private - - def can?(request) - subject = subject_of(request.subject) - resource = resource_from(request.resource) - permission = request.permission.to_sym - - policy = DeclarativePolicy.policy_for(subject, resource) - policy.can?(permission) - rescue StandardError => error - puts error.inspect - false - end - - def subject_of(encoded_token) - token = ::Authz::JWT.decode(encoded_token) - token&.claims[:sub] - end - - def resource_from(global_id) - GlobalID::Locator.locate(global_id) - end - end - end - - class AuthorizationGrant - class << self - def all - @all ||= [] - end - - def find_by(params) - case params[:grant_type] - when 'authorization_code' - authorization_code_grant(params[:code], params[:code_verifier]) - when 'refresh_token' - refresh_grant(params[:refresh_token]) - when 'client_credentials' - client_credentials_grant(params) - when 'password' - password_grant(params[:username], params[:password]) - when "urn:ietf:params:oauth:grant-type:saml2-bearer" # RFC-7522 - saml_assertion_grant(params[:assertion]) - when 'urn:ietf:params:oauth:grant-type:jwt-bearer' # RFC7523 - jwt_bearer_grant(params) - end - end - - # TODO:: implement `code_verifier` param - def authorization_code_grant(code, code_verifier) - all.find do |grant| - grant.active? && grant.code == code - end - end - - def refresh_grant(refresh_token) - raise NotImplementedError - end - - def client_credential_grant(params) - raise NotImplementedError - end - - def password_grant(username, password) - raise NotImplementedError - end - - def saml_assertion_grant(encoded_saml_assertion) - xml = Base64.decode64(encoded_saml_assertion) - # TODO:: Validate signature and prevent assertion reuse - saml_assertion = Saml::Kit::Document.to_saml_document(xml) - - user = ::Authn::User.find_by_email(saml_assertion.name_id) || - ::Authn::User.find(saml_assertion.name_id) - new(user, saml_assertion: saml_assertion) - end - - def jwt_bearer_grant(params) - raise NotImplementedError - end - - def create!(user, params = {}) - new(user, params).tap do |grant| - all << grant - end - end - end - - attr_reader :code, :user, :params - - def initialize(user, params = {}) - @user = user - @params = params - @code = SecureRandom.uuid - @exchanged_at = nil - end - - def active? - @exchanged_at.nil? - end - - def inactive? - !active? - end - - def create_access_token - raise "Invalid code" unless active? - - user.create_access_token.tap do - @exchanged_at = Time.now - end - end - - def exchange - { - access_token: create_access_token.to_jwt, - token_type: "Bearer", - issued_token_type: "urn:ietf:params:oauth:token-type:access_token", - expires_in: 3600, - refresh_token: SecureRandom.hex(32) - }.tap do |body| - if params["scope"]&.include?("openid") - body[:id_token] = user.create_id_token.to_jwt - end - end - rescue StandardError => error - { - error: error.message, - error_description: error.backtrace, - } - end - end - - class OAuthController - include ::HTTPHelpers - - def call(env) - request = Rack::Request.new(env) - - case request.request_method - when Rack::GET - case request.path - when "/oauth/authorize/continue" - if current_user?(request) - return get_authorize(request.session[:oauth_params]) - end - when "/oauth/authorize" # RFC-6749 - oauth_params = request.params.slice('client_id', 'scope', 'redirect_uri', 'response_mode', 'response_type', 'state', 'code_challenge_method', 'code_challenge') - if current_user?(request) - return get_authorize(oauth_params) - else - request.session[:oauth_params] = oauth_params - return http_redirect_to("/sessions/new?redirect_back=/oauth/authorize/continue") - end - else - return http_not_found - end - when Rack::POST - case request.path - when "/oauth/authorize" # RFC-6749 - return post_authorize(request) - when "/oauth/introspect" # RFC-7662 - params = request.content_type == "application/json" ? JSON.parse(request.body.read, symbolize_names: true) : Hash[URI.decode_www_form(request.body.read)].transform_keys(&:to_sym) - return post_introspect(params.slice(:token, :token_type_hint)) - when "/oauth/token" # RFC-6749 - params = request.content_type == "application/json" ? JSON.parse(request.body.read, symbolize_names: true) : Hash[URI.decode_www_form(request.body.read)].transform_keys(&:to_sym) - grant = AuthorizationGrant.find_by(params) - - return [404, { "Content-Type" => "application/json" }, [JSON.pretty_generate(error: 404, error_description: "Not Found")]] if grant.nil? || grant.inactive? - return [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate(grant.exchange)]] - when "/oauth/revoke" # RFC-7009 - # TODO:: Revoke the JWT token and make it ineligible for usage - return http_not_found - else - return http_not_found - end - end - http_not_found - end - - private - - def post_introspect(params) - token = ::Authz::JWT.decode(params[:token]) - return [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate(token.claims.merge(active: token.active?))]] - end - - def get_authorize(oauth_params) - template = <<~ERB - <!doctype html> - <html lang="en" data-theme="light"> - <head> - <title>IdP</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="color-scheme" content="light dark"> - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> - </head> - <body> - <main class="container"> - <nav> - <ul> - <li><strong>IdP</strong></li> - <li><a href="http://ui.example.com:8080/">UI</a></li> - </ul> - </nav> - - <h1>Authorize?</h1> - <p>Client ID: <%= oauth_params['client_id'] %></p> - <form id="authorize-form" action="/oauth/authorize" method="post"> - <input type="hidden" name="client_id" value="<%= oauth_params['client_id'] %>" /> - <input type="hidden" name="scope" value="<%= oauth_params['scope'] %>" /> - <input type="hidden" name="redirect_uri" value="<%= oauth_params['redirect_uri'] %>" /> - <input type="hidden" name="response_mode" value="<%= oauth_params['response_mode'] %>" /> - <input type="hidden" name="response_type" value="<%= oauth_params['response_type'] %>" /> - <input type="hidden" name="state" value="<%= oauth_params['state'] %>" /> - <input type="hidden" name="code_challenge_method" value="<%= oauth_params['code_challenge_method'] %>" /> - <input type="hidden" name="code_challenge" value="<%= oauth_params['code_challenge'] %>" /> - <input id="submit-button" type="submit" value="Authorize" /> - </form> - </main> - </body> - </html> - ERB - html = ERB.new(template, trim_mode: '-').result(binding) - [200, { 'Content-Type' => "text/html" }, [html]] - end - - def post_authorize(request) - params = request.params.slice('client_id', 'redirect_uri', 'response_type', 'response_mode', 'state', 'code_challenge_method', 'code_challenge', 'scope') - grant = AuthorizationGrant.create!(current_user(request), params) - case params['response_type'] - when 'code' - case params['response_mode'] - when 'fragment' - return [302, { 'Location' => "#{params['redirect_uri']}#code=#{grant.code}&state=#{params['state']}" }, []] - when 'query' - return [302, { 'Location' => "#{params['redirect_uri']}?code=#{grant.code}&state=#{params['state']}" }, []] - else - # TODO:: form post - end - when 'token' - return http_not_found - else - return http_not_found - end - end - end -end - -class IdentityProvider - include ::HTTPHelpers - - def call(env) - request = Rack::Request.new(env) - - case request.request_method - when Rack::GET - case request.path - when '/' - if current_user?(request) - return get_dashboard(request) - else - return http_redirect_to("/sessions/new") - end - when '/.well-known/openid-configuration' - return openid_metadata - when '/.well-known/oauth-authorization-server' - return oauth_metadata - when '/.well-known/webfinger' # RFC-7033 - return http_not_found - else - return http_not_found - end - end - http_not_found - end - - private - - def get_dashboard(request) - template = <<~ERB - <!doctype html> - <html lang="en" data-theme="light"> - <head> - <title>IdP</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="color-scheme" content="light dark"> - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> - </head> - <body> - <main class="container"> - <nav> - <ul> - <li><strong>IdP</strong></li> - <li><a href="http://ui.example.com:8080/">UI</a></li> - </ul> - <ul> - <li><a href="/">Home</a></li> - <li><a href="http://ui.example.com:8080/groups.html">Groups</a></li> - <li> - <form action="/sessions/delete" method="post"> - <input type="submit" value="logout" /> - </form> - </li> - </ul> - </nav> - - <h1> Hello, <%= current_user(request)[:username] %></h1> - </main> - </body> - </html> - ERB - erb = ERB.new(template, trim_mode: '-') - html = erb.result(binding) - [200, { 'Content-Type' => "text/html" }, [html]] - end - - # GET /.well-known/oauth-authorization-server - def oauth_metadata - [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ - issuer: "#{$scheme}://#{$host}/.well-known/oauth-authorization-server", - authorization_endpoint: "#{$scheme}://#{$host}/oauth/authorize", - token_endpoint: "#{$scheme}://#{$host}/oauth/token", - jwks_uri: "", # RFC-7517 - registration_endpoint: "", # RFC-7591 - scopes_supported: ["openid", "profile", "email"], - response_types_supported: ["code", "code id_token", "id_token", "token id_token"], - response_modes_supported: ["query", "fragment", "form_post"], - grant_types_supported: ["authorization_code", "implicit"], # RFC-7591 - token_endpoint_auth_methods_supported: ["client_secret_basic"], # RFC-7591 - token_endpoint_auth_signing_alg_values_supported: ["RS256"], - service_documentation: "", - ui_locales_supported: ["en-US"], - op_policy_uri: "", - op_tos_uri: "", - revocation_endpoint: "#{$scheme}://#{$host}/oauth/revoke", # RFC-7009 - revocation_endpoint_auth_methods_supported: ["client_secret_basic"], - revocation_endpoint_auth_signing_alg_values_supported: ["RS256"], - introspection_endpoint: "#{$scheme}://#{$host}/oauth/introspect", # RFC-7662 - introspection_endpoint_auth_methods_supported: ["client_secret_basic"], - introspection_endpoint_auth_signing_alg_values_supported: ["RS256"], - code_challenge_methods_supported: [], # RFC-7636 - })]] - end - - # GET /.well-known/openid-configuration - def openid_metadata - [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ - issuer: "#{$scheme}://#{$host}/.well-known/oauth-authorization-server", - authorization_endpoint: "#{$scheme}://#{$host}/oauth/authorize", - token_endpoint: "#{$scheme}://#{$host}/oauth/token", - userinfo_endpoint: "#{$scheme}://#{$host}/oidc/user/", - jwks_uri: "", # RFC-7517 - registration_endpoint: nil, - scopes_supported: ["openid", "profile", "email"], - response_types_supported: ["code", "code id_token", "id_token", "token id_token"], - response_modes_supported: ["query", "fragment", "form_post"], - grant_types_supported: ["authorization_code", "implicit"], # RFC-7591 - acr_values_supported: [], - subject_types_supported: ["pairwise", "public"], - id_token_signing_alg_values_supported: ["RS256"], - id_token_encryption_alg_values_supported: [], - id_token_encryption_enc_values_supported: [], - userinfo_signing_alg_values_supported: ["RS256"], - userinfo_encryption_alg_values_supported: [], - userinfo_encryption_enc_values_supported: [], - request_object_signing_alg_values_supported: ["none", "RS256"], - request_object_encryption_alg_values_supported: [], - request_object_encryption_enc_values_supported: [], - token_endpoint_auth_methods_supported: ["client_secret_post", "client_secret_basic", "client_secret_jwt", "private_key_jwt"], - token_endpoint_auth_signing_alg_values_supported: [], - display_values_supported: [], - claim_types_supported: ["normal", "aggregated", "distributed"], - claims_supported: [ - "acr", - "auth_time", - "email", - "email_verified", - "family_name", - "given_name", - "iss", - "locale", - "name", - "nickname", - "picture", - "profile", - "sub", - "website" - ], - service_documentation: nil, - claims_locales_supported: [], - ui_locales_supported: ["en-US"], - claims_parameter_supported: false, - request_parameter_supported: false, - request_uri_paramater_supported: false, - require_request_uri_registration: false, - op_policy_uri: "", - op_tos_uri: "", - })]] - end -end - -if __FILE__ == $0 - app = Rack::Builder.new do - use Rack::CommonLogger - use Rack::Reloader - use Rack::Session::Cookie, { domain: $host.split(":", 2)[0], path: "/", secret: SecureRandom.hex(64) } - use ::Warden::Manager do |config| - config.default_scope = :user - config.default_strategies :password - end - - map "/twirp" do - # https://github.com/arthurnn/twirp-ruby/wiki/Service-Handlers - run ::Authx::Rpc::AbilityService.new(::Authz::Rpc::Ability.new) - end - map "/oauth" do - run ::Authz::OAuthController.new - end - - map "/saml" do - run Authn::SAMLController.new($scheme, $host) - end - - map "/sessions" do - run Authn::SessionsController.new - end - run IdentityProvider.new - end.to_app - - Rackup::Server.start(app: app, Port: $port) -end diff --git a/bin/ui b/bin/ui deleted file mode 100755 index 0c1e4c4c..00000000 --- a/bin/ui +++ /dev/null @@ -1,503 +0,0 @@ -#!/usr/bin/env ruby - -require "bundler/inline" - -gemfile do - source "https://rubygems.org" - - gem "base64", "~> 0.1" - gem "erb", "~> 4.0" - gem "net-hippie", "~> 1.0" - gem "rack", "~> 3.0" - gem "rack-session", "~> 2.0" - gem "rackup", "~> 2.0" - gem "saml-kit", "1.4.0" - gem "webrick", "~> 1.0" -end - -$scheme = ENV.fetch("SCHEME", "http") -$port = ENV.fetch("PORT", 8283).to_i -$host = ENV.fetch("HOST", "localhost:#{$port}") -$idp_host = ENV.fetch("IDP_HOST", "localhost:8282") - -Net::Hippie.logger = Logger.new($stdout, level: :debug) - -class OnDemandRegistry < Saml::Kit::DefaultRegistry - def metadata_for(entity_id) - found = super(entity_id) - return found if found - - register_url(entity_id, verify_ssl: false) - super(entity_id) - end -end - -Saml::Kit.configure do |x| - x.entity_id = "#{$scheme}://#{$host}/saml/metadata.xml" - x.registry = OnDemandRegistry.new - x.logger = Logger.new("/dev/stderr") -end - -module OAuth - class Client - attr_reader :client_id, :client_secret, :http, :authz_host - - def initialize(authz_host, client_id, client_secret) - @authz_host = authz_host - @client_id = client_id - @client_secret = client_secret - @http = Net::Hippie::Client.new(headers: ::Net::Hippie::Client::DEFAULT_HEADERS.merge({ - 'Authorization' => Net::Hippie.basic_auth(client_id, client_secret), - })) - end - - def [](key) - server_metadata.fetch(key) - end - - def authorize_uri(redirect_uri:, state: SecureRandom.uuid, response_type: "code", response_mode: "query", scope: "openid") - [ - self[:authorization_endpoint], - to_query( - client_id: client_id, - state: state, - redirect_uri: redirect_uri, - response_mode: response_mode, - response_type: response_type, - scope: scope, - ) - ].join("?") - end - - def exchange(grant_type, params = {}) - with_http do |client| - client.post(self[:token_endpoint], body: body_for(grant_type, params)) - end - end - - private - - def body_for(grant_type, params) - case grant_type - when "authorization_code" - { - grant_type: grant_type, - code: params.fetch(:code), - code_verifier: params.fetch(:code_verifier, "not_implemented"), - } - when "urn:ietf:params:oauth:grant-type:saml2-bearer" - { - grant_type: grant_type, - assertion: params.fetch(:assertion), - } - else - raise NotImplementedError.new(grant_type) - end - end - - def to_query(params = {}) - params.map do |(key, value)| - [key, value].join("=") - end.join("&") - end - - def with_http - http.with_retry do |client| - yield client - end - end - - def server_metadata - @server_metadata ||= - with_http do |client| - response = client.get("http://#{authz_host}/.well-known/oauth-authorization-server") - JSON.parse(response.body, symbolize_names: true) - end - end - end -end - -module HTTPHelpers - def current_user?(request) - request.session[:access_token] - end - - def not_found - [404, { 'X-Backend-Server' => 'UI' }, []] - end - - def redirect_to(location) - if location.start_with?("http") - [302, { 'Location' => location }, []] - else - [302, { 'Location' => "#{$scheme}://#{$host}#{location}" }, []] - end - end - - def with_layout(bind) - template = <<~ERB - <!doctype html> - <html lang="en"> - <head> - <title>UI</title> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="color-scheme" content="light dark"> - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> - <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.colors.min.css"> - </head> - <body> - <main class="container"> - #{yield} - </main> - </body> - </html> - ERB - ERB.new(template, trim_mode: '-').result(bind) - end -end - -class UI - include ::HTTPHelpers - - attr_reader :oauth_client - - def initialize(oauth_client) - @oauth_client = oauth_client - end - - def call(env) - request = Rack::Request.new(env) - case request.request_method - when Rack::GET - case request.path - when "/index.html" - return get_index(request) - when "/groups.html" - if current_user?(request) - return get_groups(request) - else - return redirect_to("/oidc/new") - end - when /\A\/groups\/\d+\/projects.html\z/ - if current_user?(request) - return get_projects(request) - else - return redirect_to("/oidc/new") - end - when "/oauth/callback" - return oauth_callback(Rack::Request.new(env)) - when "/oidc/new" - return redirect_to(oauth_client.authorize_uri( - redirect_uri: "#{request.base_url}/oauth/callback" - )) - when "/saml/metadata.xml" - return metadata - when "/saml/new" - return saml_post_to_idp(Rack::Request.new(env)) - else - return redirect_to("/index.html") - end - when Rack::POST - case request.path - when "/logout" - request.session.delete(:access_token) - request.session.delete(:id_token) - request.session.delete(:refresh_token) - return redirect_to("/") - when "/saml/assertions" - return saml_assertions(Rack::Request.new(env)) - else - return not_found - end - end - not_found - end - - private - - def metadata - xml = Saml::Kit::Metadata.build_xml do |builder| - builder.embed_signature = false - builder.contact_email = 'ui@example.com' - builder.organization_name = "Acme, Inc" - builder.organization_url = "https://example.com" - builder.build_service_provider do |x| - x.name_id_formats = [Saml::Kit::Namespaces::PERSISTENT] - x.add_assertion_consumer_service("#{$scheme}://#{$host}/saml/assertions", binding: :http_post) - end - end - - [200, { 'Content-Type' => "application/samlmetadata+xml" }, [xml]] - end - - def get_index(request) - html = with_layout(binding) do - <<~ERB - <%- if current_user?(request) -%> - <nav> - <ul> - <li><a href="http://#{$idp_host}/">IdP</a></li> - <li><strong>UI</strong></li> - </ul> - <ul> - <li><a href="/index.html">Home</a></li> - <li><a href="/groups.html">Groups</a></li> - <li> - <form action="/logout" method="post"> - <input type="submit" value="Logout" /> - </form> - </li> - </ul> - </nav> - <h1>Access Token</h1> - <pre><%= request.session[:access_token] %></pre> - - <h1>ID Token</h1> - <pre><%= request.session[:id_token] %></pre> - <%- else -%> - <nav> - <ul> - <li><a href="http://#{$idp_host}/">IdP</a></li> - <li><strong>UI</strong></li> - </ul> - <ul> - <li><a href="/saml/new">SAML Login</a></li> - <li><a href="/oidc/new">OIDC Login</a></li> - </ul> - </nav> - <%- end -%> - ERB - end - [200, { "Content-Type" => "text/html" }, [html]] - end - - def oauth_callback(request) - response = oauth_client.exchange("authorization_code", code: request.params['code']) - if response.code == "200" - tokens = JSON.parse(response.body, symbolize_names: true) - request.session[:access_token] = tokens[:access_token] - request.session[:id_token] = tokens[:id_token] - request.session[:refresh_token] = tokens[:access_token] - - html = with_layout(binding) do - <<~ERB - <nav> - <ul> - <li><a href="http://#{$idp_host}/">IdP</a></li> - <li><strong>UI</strong></li> - </ul> - <ul> - <li><a href="/index.html">Home</a></li> - <li><a href="/groups.html">Groups</a></li> - <li> - <form action="/logout" method="post"> - <input type="submit" value="Logout" /> - </form> - </li> - </ul> - </nav> - <h1>Access Token</h1> - <pre style="display: none;"><%= response.body %></pre> - <pre><%= JSON.pretty_generate(request.session[:access_token]) %></pre> - ERB - end - [200, { 'Content-Type' => "text/html" }, [html]] - else - [response.code, response.header, [response.body]] - end - end - - def get_groups(request) - http = Net::Hippie::Client.new(headers: ::Net::Hippie::Client::DEFAULT_HEADERS.merge({ - 'Authorization' => Net::Hippie.bearer_auth(request.session[:access_token]) - })) - - response = http.get("http://api.example.com:8080/groups.json") - if response.code == "200" - groups = JSON.parse(response.body, symbolize_names: true) - html = with_layout(binding) do - <<~ERB - <nav> - <ul> - <li><a href="http://#{$idp_host}/">IdP</a></li> - <li><strong>UI</strong></li> - </ul> - <ul> - <li><a href="/index.html">Home</a></li> - <li><a href="/groups.html">Groups</a></li> - <li> - <form action="/logout" method="post"> - <input type="submit" value="Logout" /> - </form> - </li> - </ul> - </nav> - - <h1>Groups</h1> - <table> - <thead> - <tr> - <th>ID</th> - <th>Name</th> - <th>Organization ID</th> - <th>Parent ID</th> - <th> </th> - </tr> - </thead> - <tbody> - <%- groups.each do |group| -%> - <tr> - <td><%= group[:id] %></td> - <td><%= group[:name] %></td> - <td><%= group[:organization_id] %></td> - <td><%= group[:parent_id] %></td> - <td><a href="/groups/<%= group[:id] %>/projects.html">Projects</a></td> - </tr> - <%- end -%> - </tbody> - </table> - ERB - end - [200, { 'Content-Type' => "text/html" }, [html]] - else - [response.code, response.header, [response.body]] - end - end - - def get_projects(request) - http = Net::Hippie::Client.new(headers: ::Net::Hippie::Client::DEFAULT_HEADERS.merge({ - 'Authorization' => Net::Hippie.bearer_auth(request.session[:access_token]) - })) - - response = http.get("http://api.example.com:8080/projects.json") - if response.code == "200" - projects = JSON.parse(response.body, symbolize_names: true) - - html = with_layout(binding) do - <<~ERB - <nav> - <ul> - <li><a href="http://#{$idp_host}/">IdP</a></li> - <li><strong>UI</strong></li> - </ul> - <ul> - <li><a href="/index.html">Home</a></li> - <li><a href="/groups.html">Groups</a></li> - <li> - <form action="/logout" method="post"> - <input type="submit" value="Logout" /> - </form> - </li> - </ul> - </nav> - - <h1>Projects</h1> - <table> - <thead> - <tr> - <th>Name</th> - <th>Group ID</th> - </tr> - </thead> - <tbody> - <%- projects.each do |project| -%> - <tr> - <td><%= project[:name] %></td> - <td><%= project[:group_id] %></td> - </tr> - <%- end -%> - </tbody> - </table> - ERB - end - [200, { 'Content-Type' => "text/html" }, [html]] - else - [response.code, response.header, [response.body]] - end - end - - def saml_post_to_idp(request) - idp = Saml::Kit.registry.metadata_for("http://#{$idp_host}/saml/metadata.xml") - relay_state = Base64.strict_encode64(JSON.generate(redirect_to: '/dashboard')) - - @saml_builder = nil - uri, saml_params = idp.login_request_for(binding: :http_post, relay_state: relay_state) do |builder| - @saml_builder = builder - end - - html = with_layout(binding) do - <<~ERB - <h2>Sending SAML Request (SP -> IdP)</h2> - <textarea readonly="readonly" disabled="disabled" cols=225 rows=8><%=- @saml_builder.to_xml(pretty: true) -%></textarea> - - <form id="idp-form" action="<%= uri %>" method="post"> - <%- saml_params.each do |(key, value)| -%> - <input type="hidden" name="<%= key %>" value="<%= value %>" /> - <%- end -%> - <input id="submit-button" type="submit" value="Continue" /> - </form> - ERB - end - [200, { 'Content-Type' => "text/html" }, [html]] - end - - def saml_assertions(request) - sp = Saml::Kit.registry.metadata_for("#{request.base_url}/saml/metadata.xml") - saml_binding = sp.assertion_consumer_service_for(binding: :http_post) - saml_response = saml_binding.deserialize(request.params) - raise saml_response.errors unless saml_response.valid? - - assertion = Base64.strict_encode64(saml_response.assertion.to_xml) - response = oauth_client.exchange( - "urn:ietf:params:oauth:grant-type:saml2-bearer", - assertion: assertion, - ) - if response.code == "200" - tokens = JSON.parse(response.body, symbolize_names: true) - request.session[:access_token] = tokens[:access_token] - request.session[:refresh_token] = tokens[:access_token] - - html = with_layout(binding) do - <<~ERB - <nav> - <ul> - <li><a href="http://#{$idp_host}/">IdP</a></li> - <li><strong>UI</strong></li> - </ul> - <ul> - <li><a href="/index.html">Home</a></li> - <li><a href="/groups.html">Groups</a></li> - <li> - <form action="/logout" method="post"> - <input type="submit" value="Logout" /> - </form> - </li> - </ul> - </nav> - - <h2>Received SAML Response</h2> - <textarea readonly="readonly" disabled="disabled" cols=220 rows=40><%=- saml_response.to_xml(pretty: true) -%></textarea> - <pre id="raw-saml-response" style="display: none;"><%= request.params["SAMLResponse"] %></pre> - <pre id="xml-saml-assertion" style="display: none;"><%= saml_response.assertion.to_xml(pretty: true) %></pre> - <pre id="access-token" style="display: none;"><%= JSON.pretty_generate(request.session[:access_token]) %></pre> - ERB - end - [200, { 'Content-Type' => "text/html" }, [html]] - else - [response.code, response.header, [response.body]] - end - end -end - -if __FILE__ == $0 - app = Rack::Builder.new do - use Rack::CommonLogger - use Rack::Reloader - use Rack::Session::Cookie, { domain: $host.split(":", 2)[0], path: "/", secret: SecureRandom.hex(64) } - - run UI.new(::OAuth::Client.new($idp_host, 'client_id', 'client_secret')) - end.to_app - - Rackup::Server.start(app: app, Port: $port) -end diff --git a/casbin.conf b/casbin.conf deleted file mode 100644 index efe93e0f..00000000 --- a/casbin.conf +++ /dev/null @@ -1,17 +0,0 @@ -[request_definition] -r = subject, domain, action, object - -[policy_definition] -p = subject, domain, action, object - -[policy_effect] -e = some(where (p.eft == allow)) - -[matchers] -m =\ - (\ - (p.subject == "*" || r.subject == p.subject || regexMatch(r.subject, p.subject))\ - && (p.domain == "*" || r.domain == p.domain)\ - && (p.action == "*" || regexMatch(r.action, p.action))\ - && keyMatch(r.object, p.object)\ - ) diff --git a/casbin.csv b/casbin.csv deleted file mode 100644 index 2610d21b..00000000 --- a/casbin.csv +++ /dev/null @@ -1,14 +0,0 @@ -p, "\Agid:\/\/[a-z]+\/[A-Za-z:]+\/\d+\z", api.example.com, (GET)|(POST)|(PATCH)|(PUT)|(DELETE)|(HEAD), /*.json -p, *, *, (GET)|(HEAD), /health -p, *, *, GET, /.well-known/* -p, *, *, GET, /favicon.ico -p, "\Agid:\/\/[a-z]+\/[A-Za-z:]+\/\d+\z", idp.example.com, (GET)|(POST)|(PATCH)|(PUT)|(DELETE)|(HEAD), /twirp/authx.rpc.* -p, *, idp.example.com, (GET), / -p, *, idp.example.com, (GET)|(POST), /oauth* -p, *, idp.example.com, (GET)|(POST), /saml* -p, *, idp.example.com, (GET)|(POST), /sessions* -p, *, ui.example.com, (GET)|(POST), /oauth* -p, *, ui.example.com, (GET)|(POST), /oidc* -p, *, ui.example.com, (GET)|(POST), /saml* -p, *, ui.example.com, (GET), /*.html -p, *, ui.example.com, (POST), /logout diff --git a/cmd/authzd/main.go b/cmd/authzd/main.go index ae21e4ae..fbe89e22 100644 --- a/cmd/authzd/main.go +++ b/cmd/authzd/main.go @@ -1,18 +1,15 @@ package main import ( - "log" - "net" + "fmt" + "net/http" "github.com/xlgmokha/x/pkg/env" - "github.com/xlgmokha/x/pkg/x" - "gitlab.com/mokhax/spike/pkg/rpc" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authz.d/pkg/rpc" ) func main() { - server := rpc.New() - log.Fatal(server.Serve(x.Must(net.Listen( - "tcp", - env.Fetch("BIND_ADDR", "localhost:50051"), - )))) + bindAddr := env.Fetch("BIND_ADDR", "localhost:8080") + fmt.Printf("Listening on %v\n", bindAddr) + http.ListenAndServe(bindAddr, rpc.New()) } diff --git a/cmd/gtwy/main.go b/cmd/gtwy/main.go deleted file mode 100644 index f2a7d2e2..00000000 --- a/cmd/gtwy/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "log" - - "github.com/xlgmokha/x/pkg/env" - "gitlab.com/mokhax/spike/pkg/app" -) - -func main() { - log.Fatal(app.Start(env.Fetch("BIND_ADDR", ":8080"))) -} diff --git a/db/api/groups.csv b/db/api/groups.csv deleted file mode 100644 index 03fcf608..00000000 --- a/db/api/groups.csv +++ /dev/null @@ -1,9 +0,0 @@ -"id","organization_id","parent_id","name" -1,1,-1,"A" -2,1,-1,"B" -3,2,-1,"gitlab-org" -4,2,-1,"gitlab-com" -5,2,4,"gl-security" -6,2,5,"test-projects" -7,2,4,"support" -8,2,7,"toolbox" diff --git a/db/api/organizations.csv b/db/api/organizations.csv deleted file mode 100644 index 840de05b..00000000 --- a/db/api/organizations.csv +++ /dev/null @@ -1,3 +0,0 @@ -"id","name" -1,"default" -2,"gitlab" diff --git a/db/api/projects.csv b/db/api/projects.csv deleted file mode 100644 index 594cc390..00000000 --- a/db/api/projects.csv +++ /dev/null @@ -1,9 +0,0 @@ -"id","group_id","name" -1,1,"A1" -2,2,"B1" -3,3,"gitlab" -4,6,"eicar-test-project" -5,5,"disclosures" -6,8,"changelog-parser" -7,4,"handbook" -8,4,"www-gitlab-com" diff --git a/db/idp/users.csv b/db/idp/users.csv deleted file mode 100644 index a0194d71..00000000 --- a/db/idp/users.csv +++ /dev/null @@ -1,2 +0,0 @@ -"id","username","email","password_digest" -1,"root","root@example.org","$2a$12$pFh1DgN0JcvRAeHeTCGfiuDtuaFaV0vG7He0B6YVpkKWsBy2ZmZtO" diff --git a/doc/share/authz/ABAC.md b/doc/share/authz/ABAC.md deleted file mode 100644 index 791fdeff..00000000 --- a/doc/share/authz/ABAC.md +++ /dev/null @@ -1,57 +0,0 @@ -# Attribute-Based Access Control (ABAC) - -> Attribute-based access control (ABAC) is considered one of th emost generalized -> forms of access control as it can capture the salient features of discretionary -> access (DAC), mandatory access control (MAC) and role-based access control -> (RBAC) using appropriate attributes such as access control lists, security -> labels and roles respectively. [5] - -ABAC has been studied for a long time and many different formal models have been -proposed. - -ABAC is a logical access control model that is distinguishable because it -controls access to objects by evaluating rules against the attributes of -entities (subject and object), operations, and the environment relevant to a -request. - -As new subjects join the organization, rules and objects do not need to be -modified. As long as the subject is assigned the attributes necessary for access -to the required objects, no modifications to existing rules or object attributes -are required. - -There can be three types of attributes: - -1. Atomic-values or single valued attribute: -1. Set-valued or multi-valued attribute: -1. Structured Attribute: - -Attributes can be either: - -* Entity Attribute: a thing that can be distinctly identified. -* Non-entity Attribute: whose range is not defined on the set of entities in the - system. - -The range of an attribute is bounded or not: - -* Finite Domain Attribute: Range of this attribute type is a finite set of - attribute value. -* Infinite Domain Attribute: Range of this attribute type is a countably - infinite set of attribute values. - -## Weaknesses - -It is often claimed that attributes can express relationships, and indeed this -is trivial for direct relationships. However, the use of indirect relations, -also called multilevel or composite relations, is fundamental to ReBAC. It is -hard to see how ABAC can express long chains of relationships. It has been -suggested that ReBAC emerged to overcome this shortcoming of attributes. - -## See Also - -* [Classifying and Comparing Attribute-Based and Relationship-Based Access Control][5] -* [A Capability-based Distributed Authorization System to Enforce Context-aware Permission Sequences][6] -* [Guide to Attribute Based Access Control (ABAC) Definition and Considerations][7] - -[5]: https://dl.acm.org/doi/pdf/10.1145/3029806.3029828 -[6]: https://dl.acm.org/doi/pdf/10.1145/3532105.3535014 -[7]: https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-162.pdf diff --git a/doc/share/authz/DESIGN.md b/doc/share/authz/DESIGN.md deleted file mode 100644 index 51129a1c..00000000 --- a/doc/share/authz/DESIGN.md +++ /dev/null @@ -1,194 +0,0 @@ -# Design - -## Current - -### Architecture - -```plaintext - ------------- - | user-agent | - ------------- - | - V -----|:443|------------------------------ - | - V------------| - | | - |------| | - V V V - | ---------------------------- - |--->| authn | CI | ... | authz | - V |--------------------------| - |--->| UI | REST API | ... | - | ---------------------------- - V A - | | - |---->---->--- -``` - -## Proposed - -### Architecture - -```plaintext - ------------- - | user-agent | - ------------- - | - V -----|:8080|----------------------------------------------- - | - V - --------------- - | API Gateway | - --------------- - | - | --------------------------------- - | | IdP (saml, oidc) | - | |-------------------------------| - |--->| :http (authn) | :grpc (authz) | - | --------------------------------- - | A - ----------- | - | | | - V V | - ------ ------------ | - | UI | | REST API |----------| - ------ ------------ | - | A - |---->----------->------------| - -[UI]: ui.example.com -[REST API]: api.example.com -[IdP]: idp.example.com -``` - -SAML Login Flow - -```plantuml -@startuml -Browser -> UI: 1. Get dashboard -UI --> Browser: Generate SAML <AuthnRequest /> and redirect to IdP - -Browser -> IdP: 2. Deliver SAML <AuthnRequest /> -IdP --> Browser: 3. Redirect to Login Page -Browser -> IdP: 4. Login -IdP --> Browser: 5. Generate SAML <AuthnResponse /> with <Assertion /> and redirect to UI - -Browser -> UI: 6. Deliver SAML <AuthnResponse /> -UI -> IdP: 7. Exchange <Assertion /> for Tokens -IdP --> UI: Return `access_token` and `refresh_token` -UI --> Browser: Redirect to dashboard -Browser -> UI: Get dashboard -UI -> API: 8. Request list of groups and provide Access Token -API -> IdP: 9. Check if token is valid and check declarative policy -IdP --> API: Return result of `Ability.allowed?` -API --> UI: Return list of groups as JSON -UI --> Browser: Return list of groups as HTML -@enduml -``` - -1. `GET http://ui.example.com/saml/new` -2. `POST http://idp.example.com/saml/new` -3. `GET http://idp.example.com/sessions/new?redirect_back=/saml/continue` -4. `POST http://idp.example.com/sessions` -5. `GET http://idp.example.com/saml/continue` -6. `POST http://ui.example.com/saml/assertions` -7. `POST http://idp.example.com/oauth/token` -8. `GET http://api.example.com/groups.json` -9. `GET grpc://idp.example.com/twirp/authx.rpc.Ability/Allowed` - -OIDC Login Flow - -```plantuml -@startuml -Browser -> UI: 1. Get dashboard -UI --> Browser: Generate OAuth Grant Request and redirect to IdP - -Browser -> IdP: 2. Deliver OAuth Grant Request -IdP --> Browser: 3. Redirect to Login Page -Browser -> IdP: 4. Login -IdP --> Browser: 5. Generate Consent Screen for Authorization Code flow -Browser -> IdP: 6. Consent -IdP --> Browser: Generate Authorization Code and redirect to UI - -Browser -> UI: 7. Deliver Authorization Code Grant -UI -> IdP: 8. Exchange Authorization Code Grant for Tokens -IdP --> UI: Return `access_token` and `refresh_token` -UI --> Browser: Redirect to dashboard -Browser -> UI: Get dashboard -UI -> API: 9. Request list of groups and provide Access Token -API -> IdP: 10. Check if token is valid and check declarative policy -IdP --> API: Return result of `Ability.allowed?` -API --> UI: Return list of groups as JSON -UI --> Browser: Return list of groups as HTML -@enduml -``` - -1. `GET http://ui.example.com/oidc/new` -2. `GET http://idp.example.com/oauth/authorize` -3. `GET http://idp.example.com/sessions/new?redirect_back=/oauth/authorize/continue` -4. `POST http://idp.example.com/sessions` -5. `GET http://idp.example.com/oauth/authorize/continue` -6. `POST http://idp.example.com/oauth/authorize` -7. `GET http://ui.example.com/oauth/callback` -8. `POST http://idp.example.com/oauth/token` -9. `GET http://api.example.com/groups.json` -10. `GET grpc://idp.example.com/twirp/authx.rpc.Ability/Allowed` - -### Permissions -#### Option 1 - -| permission | scope | description | -| ---------- | ----- | ----------- | -| `read` | `gid://app/Organization/1` | Can read Org 1 resource | -| `read` | `gid://app/Organization/1/*` | Can read every resource below Org 1 hierarchy | -| `read` | `gid://app/Organization/1/Group/1` | Can read Group 1 resource | -| `read` | `gid://app/Organization/1/Group/1/*` | Can read every resource below Group 1 hierarchy | -| `read` | `gid://app/Organization/1/Group/1/Project/1` | Can read project 1 | -| `read` | `gid://app/Project/1` | Can read project 1 resource (short circuit example) | -| `read` | `gid://app/Organization/1/Group/1?attributes[]=name&attributes[]=description` | Can read name and description of Group 1 resource | - -Example: - -The following example allows the subject of the token to read all of the descendant resources of `Project 1` and `Project 2` and it can read `Project 3`. - -```json -{ - "sub": "gid://User/17", - "scope": { - "read": [ - "gid://app/Organization/1/Group/1/Project/1/*", - "gid://app/Organization/1/Group/1/Project/2/*", - "gid://app/Organization/1/Group/2/Project/3" - ] - } -} -``` - -#### Option 2 - -Encode access and scope directly into the name of the permission. - -| permission | description | -| ---------- | ----------- | -| `read:organization:1` | Can read Org 1 resource | -| `read:organization:1:*` | Can read every resource below Org 1 hierarchy | -| `read:organization:1:group:*` | Can read Group 1 resource | -| `read:organization:1:group:1:*` | Can read every resource below Group 1 hierarchy | -| `read:organization:1:group:1:project:1` | Can read project 1 | -| `read:project:1` | Can read project 1 resource (short circuit example) | -| `read:organization:1:group:1:attributes[]=name&attributes[]=description` | Can read name and description of Group 1 resource | - -Example: - -```json -{ - "sub": "gid://User/17", - "scope": [ - "read:organization:1:group:1:project:1:*", - "read:organization:1:group:1:project:2:*", - "read:organization:1:group:2:project:3" - ] -} -``` diff --git a/doc/share/authz/EXPERIMENT.md b/doc/share/authz/EXPERIMENT.md deleted file mode 100644 index 0460fe39..00000000 --- a/doc/share/authz/EXPERIMENT.md +++ /dev/null @@ -1,42 +0,0 @@ -## Experiments - -### Twirp + gRPC (AuthZ) - -This experiment exposes a gRPC endpoint that aligns with the [`Ability.allowed?(subject, permission, resource)`][1] interface from GitLab's declarative authorization logic. - -It demonstrates a headless authorization service that provides a low-latency decision point for other services to verify permissions. - -Actors in this experiment: - -* Headless authz service: A facade over GitLab’s existing declarative policies. -* API (Resource Server in OAuth terms): A slimmed-down GitLab REST API that delegates authorization decisions to the authz service. - -### SAML, OIDC, OAuth - -This experiment showcases how a separate authx service can handle both authentication and authorization using standard protocols: - -* SAML & OIDC for authentication -* OAuth for authorization - -Actors in this experiment: - -* Authx service: Acts as a SAML Identity Provider and an OAuth Authorization Server. -* API: A slimmed-down GitLab REST API. - -### API Gateway - -This experiment explores a stateless authorization mechanism by integrating a policy DSL (such as [Casbin][3]) into a reverse proxy. -Authorization decisions are made early in the request pipeline based on HTTP request headers and body content. - -### Sidecar Process - -This experiment demonstrates a sidecar approach for making authorization decisions within an nginx process. -Inspired by [Open Policy Agent][4] deployments. This experiment: - -* Uses lua bindings in nginx to connect to a local client process. -* The client process proxies requests to a gRPC based policy decision service. - - -[1]: https://gitlab.com/gitlab-org/gitlab/-/blob/e1f6db024561e35462ac8d9f54b8f9678f6ed6ee/app/models/ability.rb#L73 -[3]: https://casbin.org/ -[4]: https://www.openpolicyagent.org/ diff --git a/doc/share/authz/FAQ.md b/doc/share/authz/FAQ.md deleted file mode 100644 index 8e73beb2..00000000 --- a/doc/share/authz/FAQ.md +++ /dev/null @@ -1,33 +0,0 @@ -# Frequently Asked Question (FAQ) - -* Q: Are there permissions that do not cascade down the group hierarchy? -* Q: How do we define the scope of a permission? (hierarchical?) -* Q: What is the unique identifier for each security principal across service boundaries? (i.e. bigint, ulid, uuid, email) -* Q: What permissions do each of the standard roles have today? -* Q: How does a permission cascade down a group hierarchy? - -``` -Organization - Group A - * Roles - * Developer - * Maintainer - * Custom A - * base: developer - * permissions: - * admin_vulnerability: true - * read_vulnerability: true (implicitly) - * Custom B - * base: maintainer - * permissions: - * Doesn't really matter because Maintainer has all the permissions available via a custom role. <- Fact check this - Group Aa - Project Aa1 - Project Aa2 - Group Aaa - Project Aaa1 - Project Aaa2 -``` - -* Q: If a user has a membership at `Group A`, does the permissions associated with that -membership cascade down to `Group Aa` and `Group Aaa`? diff --git a/doc/share/authz/POLICY.md b/doc/share/authz/POLICY.md deleted file mode 100644 index ab2e8f1a..00000000 --- a/doc/share/authz/POLICY.md +++ /dev/null @@ -1,124 +0,0 @@ -# Policy - -> Policy is a planned system of rules and guidelines that directs users and automation to execute within purposeful boundaries. [1][1] - -The parts of a policy include: [1][1] - -* name: used to label the policy for future reference -* purpose: the reason this policy exists -* situation: the context in which the policy will be used -* rules: individual controls or prescribed behaviours; -* actions: action taken if a policy rule is violated - -> A policy is a statement that declares which principals are explicitly -> permitted, or explicitly forbidden, to perform an action on a resource. - [2][2] - -## Policy Language - -A policy language facilitates: [3][3] - -1. the specification of composite policies, which in turn forms the basis of trust delegation. -1. **the static analysis of policies and system configuration.** - -### Policy as Code (PaC) - -These are policies that are written, stored, managed and interpreted as code -artifacts. - -> A policy engine is a program or process that is able to ingest -> machine-readable policies and apply them to a particular problem domain to -> constrain the behaviour of network resources. [1][1] - -PaC policy engine characteristics: [1][1] - -* Ingeting machine-readable policies (PaC) -* Applying policies to specific problem domains (data) -* Constraining behaviors (outcomes) - -```plaintext - ---------- - | Policy |--------- A - ---------- | / \ - V / \ - -------- --------- / \ -------------- -------- - | Data |------>| Input |--->< match >--->| Evaluation |--->( Outcom ) - -------- --------- \ / -------------- -------- - A \ / - --------- | \ / - | Query |---------- V - --------- -``` - -Selection Criteria: [1][1] - -* Alignment - - Technical Capabilities of team. - - Internal strategy for how tools and applications are adopted/managed. - - Fits the need and internal standards driving the decision - - Primary use cases match our use cases -* Analytics - - logging - - metrics - - auditing -* Automation - - CI/CD Pipelines - - Automated Deployments -* Documentation - - Examples - - Patterns - - Understandable -* Adoption - - Who is using this? - - How much adoption has this project seen? - - Active? - - Project Maturity - - Support Model - - Intuitive -* Complexity - - Installation - - Deployment - - Configuration - - Operation Modes (server, library, CLI) -* Reporting - * Standard reporting tools e.g. [OSCAL](https://pages.nist.gov/OSCAL/) -* Security - * Risks, vulnerabilities - * Tools and processes for security issue discovery -* Extensibility - * Can custom code be written to extend the language. - -Scorecard [1][1] - -| Selection Criteria | Casbin | Cedar | Rego | -| ------------------ | ------ | ----- | ---- | -| Alignment | | | | -| Analytics | | | | -| Adoption | | | | -| Automation | | | | -| Documentation | | | | -| Complexity | | | | -| Reporting | | | | -| Security | | | | -| Extensibility | | | | -| Total | | | | - -### Cedar - -### Rego - -[Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) is a declarative assertion language that provides reasoning. This is a DSL -for applying reasoning and assertions to domain-agnostic, structured data. - -* [Regorus](https://github.com/microsoft/regorus) - * [Go binding](https://github.com/microsoft/regorus/tree/main/bindings/go) - * [Ruby binding](https://github.com/microsoft/regorus/tree/main/bindings/ruby) - -## See Also - -* [Zanzibar](./ZANZIBAR.md) -* [Dafny](https://dafny.org) -* [Policy as Code by Jimmy Ray][1] - -[1]: https://learning.oreilly.com/library/view/policy-as-code/ -[2]: https://docs.cedarpolicy.com/overview/terminology.html#term-policy -[3]: https://ucalgary.scholaris.ca/server/api/core/bitstreams/833a86a8-eb7f-4c50-af4d-696b8deb6fd8/content diff --git a/doc/share/authz/RBAC.md b/doc/share/authz/RBAC.md deleted file mode 100644 index 2f0054a6..00000000 --- a/doc/share/authz/RBAC.md +++ /dev/null @@ -1,103 +0,0 @@ -# Role-Based Access Control (RBAC) - -Assigns permissions to roles, which are collections of permissions related to specific job functions. [1][1] - -This style of access control aligns with how humans organize themselves within -organizations by assigning job functions to roles. This model is simple and -aligns well with how humans operate within their job function. - -This model also helps to align security objectives with higher level -organizational policy (.e.g. ethics, privacy, administration). This type of -model requires centralized control and enforcement. - -> The act of granting membership and specifying transactions for a role is loosely -> analogous to the process of clearing users (granting membership) and the -> labeling (associate operation sensitivities) of objects ... - Role-Based Access Controls by Ferraiolo, Kuhn Et el. - -> A role can be thought of as a set of transactions that a user or set of users -> can perform within the context of an organization. - Role-Based Access Controls by Ferraiolo, Kuhn Et el. - -Roles are group oriented and they provide a means of naming and describing -many-to-many relationships between individuals and rights. - -1. For each subject, the active role is the one that the subject is currently using: - - ``` - AR(s: subject) = { the active role for subject s}. - ``` - -2. Each subject may be authorized to perform one or more roles: - - ``` - RA(s: subject) = { authorized roles for subject s }. - ``` - -3. Each role may be authorized to perform one or more transactions: - - ``` - TA(r: role) = { transactions authorized for role r}. - ``` - -4. Subjets may execute transactions. The predicate `exec(s,t)` is true if - subject `s` can execute transaction `t` at the current time, otherwise it is - false: - - ``` - exec(s :subject, t: tran) = true iff subject `s` can execute transaction `t` - ``` - -Three basic rules are required: - -1. Role assignment: A subject can execute a transaction only if the subject has - selected or been assigned a role -2. Role authorization: A subject's active role must be authorized for the - subject -3. Transaction authorization: A subject can execute a transaction only if the - transaction is authorized for the subject's active role - -Another user of RBAC is to support integrity. One aspect of integrity is a -requirement that data and processes be modified only in authorized ways by -authorized users. - -The problem of determining whether data have been modified only in authorized -ways can be as complex as the transaction that did the modification. For this -reason, the practical approach is for transactions to be certified and -trusted. If transactions must be trusted then _access control can be incorporated -directly into each transaction_. - -RBAC makes a decision based on the subject's association with a role. RBAC does -not easily support multi-factor decisions. RBAC role assignments tend to be -based upon more static organizational positions, presenting challenges in -certain RBAC architectures where dynamic access control decisions are required -(.e.g. `CI_JOB_TOKEN`). Trying to implement these kidns of access control -decisoins would require the creation of numerous roles that are ad hoc and -limited in membership, leading to what is often termed "role explosion". - -ABAC avoids the need for explicit authorizations to be directly assigned to -individual subjects prior to a request to perform an operation on the object. - -> ABAC: An access control method where subject requests to perform operations on -> objets are granted or denied based on assigned attributes of the subject, -> assigned attributes of the object, environment conditions, and a set of -> policies that are specified in terms of those attributes and conditions. - -* Attributes: characteristics of the subject, object, or environment conditions. -* Subject: is a human or or non-person entity (NPE) that issues access requests - to perform operations on objects. -* Object: a system resource for which access is managed by the ABAC system -* Operation: is the execution of a function at the request of a subject upon an - object. (e.g. read, write, edit, delete, copy, execute and modify) -* Policy: is the representation of rules or relationships that makes it possible - to determine if a requested access should be allowed. -* Environment conditions: operational or situational context in which the access - request occurs. - -> Roles can inherit from each other and imply permissions. - [1][1] - -## See also - -* [Role-Based Access Controls][1] -* [Zanzibar][2] - -[1]: https://csrc.nist.gov/files/pubs/conference/1992/10/13/rolebased-access-controls/final/docs/ferraiolo-kuhn-92.pdf -[2]: https://storage.googleapis.com/gweb-research2023-media/pubtools/5068.pdf diff --git a/doc/share/authz/README.md b/doc/share/authz/README.md deleted file mode 100644 index 5b7da3fb..00000000 --- a/doc/share/authz/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# Authz - -## Access Control Models - -Access Controls provide a means of restricting access to objects based on the -identity of subjects and/or groups to which they belong. - -* Role-Based Access Control ([RBAC](./RBAC.md)) -* Relationship-Based Access Control ([ReBAC](./ReBAC.md)) -* Attribute-Based Access Control ([ABAC](./ABAC.md)) - -Authentication (Authn) is used to determine that users or systems are who they -claim to be and provide proof in the form of identity principals and attributes. - -Authorization (Authz) is used to decide what privileges an actor has within a -system. - -## Policy - -* [What is a policy?](./POLICY.md) -* Policy Language Evaluation - * Casbin - * Cedar - * [Dafny](https://dafny.org/) - * Rego - -Criteria for evaluating policy languages: - -* Must be able to model different types of access control models (RBAC, ReBAC, ABAC) -* Must be able to perform static analysis -* Must be actively supported -* Must have concise documentation -* Must provide ability to extend language using Ruby/Golang for describing complex policies. -* Must have a compatible license that permits the way that we can use it. - -Ideally, we must be able to model the following relationships: - -| type | required | -| ---- | -------- | -| `user-to-resource` | required | -| `resource-to-resource` | required | -| `user-to-user` | not required | - -Note: `user-to-user` relationships are not in the current access control model. - -## Architecture - -```plaintext - ------------------ ------- ------------- - | Users/Services |--->| PEP |--->| Resources | - ------------------ ------- ------------- - | A - V | - ------- ------------ ------- - | PDP |-->| Policies |<---| PAP | - ------- ------------ ------- - | A A - V | | - ------- ----------------- - | PIP | | Administrator | - ------- ----------------- - -PAP: Policy Administration Point -PDP: Policy Decision Point -PEP: Policy Enforcement Point -PIP: Policy Information Point -``` - -* [Kubernetes Policy Management](https://github.com/kubernetes/sig-security/blob/main/sig-security-docs/papers/policy/kubernetes-policy-management.pdf) diff --git a/doc/share/authz/ReBAC.md b/doc/share/authz/ReBAC.md deleted file mode 100644 index 9202e0c4..00000000 --- a/doc/share/authz/ReBAC.md +++ /dev/null @@ -1,149 +0,0 @@ -# Relationship-Based Access Control (ReBAC) - -> Authorization decisions are based on the relationship between the resource owner -> and the resource accessor in a social network maintained by the protection -> system. [1] - -A Social Network System (SNS) maintains a social network for at least two reason: - -1. It is used by the users to navigate the information space of the system -2. The social network is used as a basis for formulating the access control - policies of user contributed resources. - -Access Control Paradigm: - -1. the explicit tracking of one or more social networks by the protection system -1. the expression of access control policies in terms of the relationship - between the resource owner and the resource accessor - -Suited for domains in which relationship and authorization decisions are from -the structure of trust that is inherent in the application domain rather than -subjective assessment of users. - -It is more natural to base authz decisions on whether the resource owner and -accessor are in a particular kind of relationship. - -In a standard RBAC system, when a permission `p` is assigned to role `R`, we are -essentially formulating the following policy: `grant p to user u if R(u)`. - -PriMA is another recently proposed privacy protection mechanism for SNSs. - -Unlike [RBAC][4] and [ABAC][3], ReBAC policies deal with relational policies -rather than unary predicates on attributes and roles. - -In, Online Social Network (OSN) applications, authorization for users' access to -specific content is typically based on ther interpersonal relationships between -the accessing user and content owner. OSN ReBAC models user user-to-user -relationships. - -The user of indirect relations, also called multilevel or composite relations, -is fundamental to ReBAC (e.g. friend of friend). - -Recently, researchers have proposed extended ReBAC models applicable to other -computing systems beyond OSNs. - -Most ReBAC models consider `user-to-user` and possibly `user-to-resource` -relationshps. Very few consider `resource-to-resource` relationships. Models -that consider `resource-to-resource` relationships typically do so through -users. - -## Access Control Policies - -Let `U` be the set of all users in the system. -Accesses are directed against resources. A resource may represent one or more -objects or certain system operations. Let `R` be the set of resources protected -by the SNS. A typical member of `R` is denoted by `r`. - -Assocated with every access request are therefore the following: - -* a protected resource that is being accessed -* the owner of that resource -* the accessor of that resource who requests access. - -Owner of a resource implies that the accessor must be in a specific kind of -relationship with the owner in order be granted. Huh? - -Associated with every resource is an `access control policy`. -Policy is modeled as a ternary predicate: `U x U x G(U, I) => {0, 1}`. - -## Protection System - -A protection system `N` is a 7-tuple `(I, U, R, C, C0, policy, owner)` where: - -* `I` is the set of relation identifiers (See my question in the README about resource identifiers in our system) -* `U` is a finite set of users in the system -* `R` is a finite set of resources to be protected by the system. -* `C` is a _infinite_ universe of `access contexts`. - * `C0` is the root context. (* Could this be the root `Organization` that a `User` belongs to?) -* `R => PP(U, I)` assigns a policy predicate to every resource in the system. (This means that every resource is addressable through a universal identifier, right? Goodbye `bigint`? Yay!) -* `owner: R -> U` is a function that assigns an owner to every resource in the system. - -Where the access control policy of a resource comes from doesn't matter. The -possibilities are: - -1. Mandatory: Some policies are mandated by the system administrator -1. Discretionary: The resource owners are responsible for specifying their - access control policies -1. Policy Vocabulary: A set of policy predicates from which users take their - picks. (friends, friends-of-friends) - -## Protection State - -Given a protection system `N = {I,U,R,C,C0,policy,owner}`, a protection state is -a triple `{C,sn,extends}` composed of the following elements: - -* `C`: is the set of active contexts in the state. This set is infinite and - non-empty. -* function `sn : C -> G(U,I)` that maps each context of the state to a social - network `sn(s)` records the relationships that have been articulated in - context `c`. -* `extends ~= C x C` is a binary relation defined over `C`, such that: - * a: the directed graph is a tree - * b: `c0` is the root of the tree - * c: if `(c1,c2) ~= extends` then `c1` is the child of `c2` in the tree. The - extends relationship defines a **context hierarchy**. - -## Authorization - -Authz is achieved by consulting relationships in a social network. Authorization -decisions are made primarily by consulting the relationship between accessor and -the owner. In a real implementations, it is possible for the system to have a -hybrid authorization scheme that is both relationship based and role based. - -Relationship inheritance allows relationships articulated in ancestor contexts -to be inherited by the effictive social network of descendant contexts. The -social network of a child context contains no less relationships than that of a -parent context. - -## Policy Language - -It is desirable to have a [policy language](./POLICY.md) for specifying ReBAC policies. - -A policy language facilitates: - -1. the specification of composite policies, which in turn forms the basis of trust delegation. -1. **the static analysis of policies and system configuration.** - -## Context Hierarchy - -The context hierarchy assumes a tree shape: i.e., only single inheritance is permitted. -Multiple inheritance corresponds to a more flexible means of constraining when -relationships can be "activated" simultaneously. - -## Conclusion - ->Relationship-Based Access Control works best in application domains in which ->binary relations are more natural for expressing authorization decisions than ->unary relations (e.g., roles). - -## See also - -* [Relationship-Based Access Control: Protection Model and Policy Language by Philip W. L. Fong][1] -* [Learning Relationship-Based Access Control Policies from Black-Box Systems][2] -* [Classifying and Comparing Attribute-Based and Relationship-Based Access Control][5] - -[1]: https://cspages.ucalgary.ca/~pwlfong/Pub/codaspy2011.pdf -[2]: https://dl.acm.org/doi/pdf/10.1145/3517121 -[3]: ./ABAC.md -[4]: ./RBAC.md -[5]: https://dl.acm.org/doi/pdf/10.1145/3029806.3029828 diff --git a/doc/share/authz/SLIDES.md b/doc/share/authz/SLIDES.md deleted file mode 100644 index c14387bc..00000000 --- a/doc/share/authz/SLIDES.md +++ /dev/null @@ -1,207 +0,0 @@ -# Authx = Authn + Authz - -* Authentication: Are you who you say you are? -* Authorization: Are you allowed to do that? - -# Authx - Examples - -1. Travel by Plane (High security context) - * Authentication: Passport - * Authorization: Boarding Pass -1. Travel by Bus (Low security context) - * Authentication: Not required - * Authorization: Bus ticket - -# Authx - -The Resource Server provides the security context and knows if the resource that -is being access requires a high or low security context. - -# Authx - -Not every resource requires a high security context. - -i.e. we don't need to make a network call to the PDP for every single authorization decision if the security context is low. - -# Authx - Challenges - -* PKI: key rotation, revocation, signing, encryption -* Uptime Guarantees -* Auditability -* Complexity -* Interoperability -* Extensibility -* Observability -* ... - -# OAuth 2.x - -OAuth is for Authorization. - -# OAuth 2.x - Protocol Flow - -```plaintext - +--------+ +---------------+ - | |--(A)- Authorization Request ->| Resource | - | | | Owner | - | |<-(B)-- Authorization Grant ---| | - | | +---------------+ - | | - | | +---------------+ - | |--(C)-- Authorization Grant -->| Authorization | - | Client | | Server | - | |<-(D)----- Access Token -------| | - | | +---------------+ - | | - | | +---------------+ - | |--(E)----- Access Token ------>| Resource | - | | | Server | - | |<-(F)--- Protected Resource ---| | - +--------+ +---------------+ -``` - -https://datatracker.ietf.org/doc/html/rfc6749#section-1.2 - -# OAuth 2.x - Protocol Endpoints - -The authorization process utilizes two authorization server endpoints (HTTP resources): - -- Authorization endpoint - used by the client to obtain authorization from the resource owner via user-agent redirection. -- Token endpoint - used by the client to exchange an authorization grant for an access token, typically with client authentication. - -https://datatracker.ietf.org/doc/html/rfc6749#section-3 - -# OAuth 2.x - Authorization Grants - -* Authorization Code: `authorization_code` -* JWT Bearer: `urn:ietf:params:oauth:grant-type:jwt-bearer` -* Refresh Token: `refresh_token` -* SAML Assertion: `urn:ietf:params:oauth:grant-type:saml2-bearer` - -# OAuth 2.x - Authorization Code Grant Protocol Flow - -```plaintext - +----------+ - | Resource | - | Owner | - | | - +----------+ - ^ - | - (B) - +----|-----+ Client Identifier +---------------+ - | -+----(A)-- & Redirection URI ---->| | - | User- | | Authorization | - | Agent -+----(B)-- User authenticates --->| Server | - | | | | - | -+----(C)-- Authorization Code ---<| | - +-|----|---+ +---------------+ - | | ^ v - (A) (C) | | - | | | | - ^ v | | - +---------+ | | - | |>---(D)-- Authorization Code ---------' | - | Client | & Redirection URI | - | | | - | |<---(E)----- Access Token -------------------' - +---------+ (w/ Optional Refresh Token) -``` - -# OAuth 2.x - Implicit Grant (not a recommendation) - -```plaintext - +--------------------+ - | Resource Owner | - +--------------------+ - ^ - (B) - +----|-----+ Client Identifier +---------------+ - | +----(A)-- & Redirection URI --->| Authorization | - | User- | | Server | - | Agent -|----(B)-- User authenticates -->| | - | |<---(C)--- Redirection URI ----<+---------------+ - | | with Access Token - | | +---------------+ - | |----(D)--- Redirection URI ---->| Web-Hosted | - | | without Fragment | Client | - | | | Resource | - | (F) |<---(E)------- Script ---------<+---------------+ - +-|--------+ - (A) (G) Access Token - ^ v - +---------+ - | Client | - +---------+ -``` - -# OAuth 2.x - Refresh Token Grant Protocol Flow - -```plaintext - +--------+ +---------------+ - | |--(A)------- Authorization Grant --------->| | - | | | | - | |<-(B)----------- Access Token -------------| | - | | & Refresh Token | | - | | | | - | | +----------+ | | - | |--(C)---- Access Token ---->| | | | - | | | | | | - | |<-(D)- Protected Resource --| Resource | | Authorization | - | Client | | Server | | Server | - | |--(E)---- Access Token ---->| | | | - | | | | | | - | |<-(F)- Invalid Token Error -| | | | - | | +----------+ | | - | | | | - | |--(G)----------- Refresh Token ----------->| | - | | | | - | |<-(H)----------- Access Token -------------| | - +--------+ & Optional Refresh Token +---------------+ -``` - -# OpenID Connect (OIDC) - -OIDC adds Authn to OAuth. - -# OIDC - Protocol Flow - -OIDC = Authn + OAuth - -```plaintext -+--------+ +--------+ -| | | | -| |---------(1) AuthN Request-------->| | -| | | | -| | +--------+ | | -| | | | | | -| | | End- |<--(2) AuthN & AuthZ-->| | -| | | User | | | -| RP | | | | OP | -| | +--------+ | | -| | | | -| |<--------(3) AuthN Response--------| | -| | | | -| |---------(4) UserInfo Request----->| | -| | | | -| |<--------(5) UserInfo Response-----| | -| | | | -+--------+ +--------+ -``` - -https://openid.net/specs/openid-connect-core-1_0.html#Overview - -# WLIF - -TODO:: Add a protocol flow diagram - -* https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation#how-it-works -* https://docs.google.com/document/d/1XyuQXuUJE0kGC2jqy_vaLPGxAFjzMvJWOS74QoP7UA8/ - -# Primitives - -We need: - -* PKI: Certificate Authority generate and sign intermediate certs -* OAuth 2.x Authorization Server -* OIDC Provider (OP) diff --git a/doc/share/authz/ZANZIBAR.md b/doc/share/authz/ZANZIBAR.md deleted file mode 100644 index fc49ab2d..00000000 --- a/doc/share/authz/ZANZIBAR.md +++ /dev/null @@ -1,51 +0,0 @@ -# Zanzibar - -Zanzibar is a planet-scale distributed ACL storage and evaluation system. -Zanzibar's data model supports permissions, users, groups, and inheritance as -found in the above systems. [1][1] - -Zanzibar servers delegate checks and reads to each other based on consistent -hashing. Both the caller and the callee sides of the delegated operations cache -the results to prevent hot spots. Zanzibar handles 22 million internal RPCs per -second. In-memory caching handles approximately 200 million lookups per second -at peak. - -Clients include: - -* Google Calendar -* Google Cloud -* Google Drive -* Google Maps -* Google Photos -* YouTube - -Lessons learned - -* Access control patterns vary widely -* Freshness requirements are often but not always loose. (i.e. moderate staleness during ACL evaluation is okay) -* Performance optimizations - * Request hedging is key to reducing tail latency. (Search issues 10s-100s of authz checks to serve a single set of search results.) - * Hot-spot mitigation is critical for high availability: some workloads create hot spots in ACL data that can overwhelm database servers. - * Performance isolation is indispensible to protect against misbehaving clients. (e.g. new feature launch that is popular. Unpredicatable usage patterns.) - -Roles are similar to Zanzibar relations. Roles can inherit from each other and -imply permissions. Clients have implemented RBAC policies on top of Zanzibar's -namespace configuration. - -Most IAM systems offer: - -* assigning users to roles or groups -* domain-specific policy languages -* API to edit ACLs. - -These systems have a communit unified ACL storage and and RPC-based API. - -It evaluates deeply or widely nested group membership with Leopard, a -specialized index for efficient computation of set operations with snapshot -consistency. - -## See Also - -* [1][1] - -[1]: https://storage.googleapis.com/gweb-research2023-media/pubtools/5068.pdf diff --git a/doc/share/authz/todo/001_ldap.md b/doc/share/authz/todo/001_ldap.md deleted file mode 100644 index 408cc771..00000000 --- a/doc/share/authz/todo/001_ldap.md +++ /dev/null @@ -1,19 +0,0 @@ -As an `Owner`, I want to `control group membership via LDAP`, so that `I can manage users in my company using my existing LDAP server`. - -# SYNOPSIS - -An external LDAP server should be able to synchronize data to the IdP. - -# DESCRIPTION - -# SEE ALSO - -* [ ] TBD - -# Tasks - -* [ ] TBD - -# Acceptance Criteria - -* [ ] TBD diff --git a/doc/share/authz/todo/002_hierarchical_membership.md b/doc/share/authz/todo/002_hierarchical_membership.md deleted file mode 100644 index 224eed7a..00000000 --- a/doc/share/authz/todo/002_hierarchical_membership.md +++ /dev/null @@ -1,19 +0,0 @@ -As an `Owner`, I want to `manage group membership`, so that `I can manage users in my company`. - -# SYNOPSIS - -Owners of an Organization can create group hierarchies and manage memberships to those groups. - -# DESCRIPTION - -# SEE ALSO - -* [ ] TBD - -# Tasks - -* [ ] TBD - -# Acceptance Criteria - -* [ ] TBD diff --git a/doc/share/authz/todo/003_workload_identity_federation.md b/doc/share/authz/todo/003_workload_identity_federation.md deleted file mode 100644 index a93353a7..00000000 --- a/doc/share/authz/todo/003_workload_identity_federation.md +++ /dev/null @@ -1,21 +0,0 @@ -As an `Operator`, I want to `integrate multicloud workloads`, so that `I can operate multiple clouds include on-premises`. - -# SYNOPSIS - -I have no idea what workload identity federation is but it sounds like a neat -way to federate authn to an external/central identity provider to interop -between multiple clouds. - -# DESCRIPTION - -# SEE ALSO - -* https://cloud.google.com/iam/docs/workload-identity-federation - -# Tasks - -* [ ] TBD - -# Acceptance Criteria - -* [ ] TBD diff --git a/doc/share/authz/todo/004_acme_protocol.md b/doc/share/authz/todo/004_acme_protocol.md deleted file mode 100644 index 93628f77..00000000 --- a/doc/share/authz/todo/004_acme_protocol.md +++ /dev/null @@ -1,69 +0,0 @@ -As an `Operator`, I want to `use the ACME protocol`, so that `I have a standards based way to manage PKI`. - -# SYNOPSIS - -Use the ACME protocol to generate TLS PKI. - -# DESCRIPTION - -Below is an example startup configuration for using the ACME protocol in golang -and distributing the key material using file storage. The file storage should be -replaced with a distributed blob storage that is locked down. This also uses -the `STEPPATH` environment variable to access an internal root certificate -authority. - -```golang -func WithAcmeTLS(ctx context.Context, directoryURL string, cacheDir string) cfg.Option { - storageFor := func(config *cfg.Config) certmagic.Storage { - return &certmagic.FileStorage{Path: cacheDir} - } - return func(config *cfg.Config) { - host := os.Getenv("HOST") - tls := srv.NewTLS(ctx, host, storageFor(config), []certmagic.ACMEIssuer{ - { - Agreed: true, - CA: directoryURL, - DisableHTTPChallenge: true, - Email: "everyone@example.com", - TestCA: directoryURL, - TrustedRoots: newCertPool(), - AltTLSALPNPort: bindingPort(), - }, - }) - config.TLS = x.Must(tls.Config()) - } -} - -func newCertPool() *x509.CertPool { - certPool := x.Must(x509.SystemCertPool()) - certPool.AddCert(func() *x509.Certificate { - block, _ := pem.Decode(x.Must(ioutil.ReadFile( - filepath.Join(os.ExpandEnv("$STEPPATH"), "/certs/root_ca.crt"), - ))) - return x.Must(x509.ParseCertificate(block.Bytes)) - }()) - return certPool -} - -func bindingPort() int { - parts := strings.SplitN(os.Getenv("BIND_ADDR"), ":", 2) - bindPort, err := strconv.Atoi(parts[1]) - if err != nil { - bindPort = 0 - } - return bindPort -} -``` - -# SEE ALSO - -* [RFC-8555](https://datatracker.ietf.org/doc/html/rfc8555) -* [$STEPPATH](https://smallstep.com/docs/step-cli/reference/path/#examples) - -# Tasks - -* [ ] TBD - -# Acceptance Criteria - -* [ ] TBD diff --git a/doc/share/authz/todo/005_open_pubkey.md b/doc/share/authz/todo/005_open_pubkey.md deleted file mode 100644 index 92b0b7a8..00000000 --- a/doc/share/authz/todo/005_open_pubkey.md +++ /dev/null @@ -1,20 +0,0 @@ -As an `Owner`, I want to `enable ssh access via open pubkey`, so that `have a standard based approach to connect over SSH`. - -# SYNOPSIS - -Research OpenPubKey to see how it operates on top of OIDC to provide ephemeral -SSH keys for temporary access. - -# DESCRIPTION - -# SEE ALSO - -* https://docs.bastionzero.com/openpubkey-ssh - -# Tasks - -* [ ] TBD - -# Acceptance Criteria - -* [ ] TBD diff --git a/doc/share/authz/todo/006_zero_knowledge_proof.md b/doc/share/authz/todo/006_zero_knowledge_proof.md deleted file mode 100644 index eb3984e9..00000000 --- a/doc/share/authz/todo/006_zero_knowledge_proof.md +++ /dev/null @@ -1,17 +0,0 @@ -As an `Developer`, I want to `understand what a zero knowledge proof is`, so that `I can understand how to be considerate of privacy`. - -# SYNOPSIS - -# DESCRIPTION - -# SEE ALSO - -* https://dl.acm.org/doi/pdf/10.1145/3708622.3708634 - -# Tasks - -* [ ] TBD - -# Acceptance Criteria - -* [ ] TBD @@ -1,242 +1,111 @@ -module gitlab.com/mokhax/spike +module gitlab.com/gitlab-org/software-supply-chain-security/authorization/authz.d go 1.24.0 require ( - github.com/caddyserver/certmagic v0.22.2 github.com/casbin/casbin/v3 v3.0.0-beta.7 - github.com/cedar-policy/cedar-go v1.1.1 - github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3 + github.com/cedar-policy/cedar-go v1.2.1 + github.com/lestrrat-go/jwx/v3 v3.0.1 github.com/magefile/mage v1.15.0 - github.com/playwright-community/playwright-go v0.5001.0 github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 - github.com/xlgmokha/x v0.0.0-20250404223908-0b29f54f06e7 - go.uber.org/zap v1.27.0 - golang.org/x/oauth2 v0.28.0 + github.com/twitchtv/twirp v8.1.3+incompatible + github.com/xlgmokha/x v0.0.0-20250430185455-b691eda27477 google.golang.org/grpc v1.71.0 google.golang.org/protobuf v1.36.6 ) require ( - cloud.google.com/go v0.118.3 // indirect cloud.google.com/go/auth v0.15.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect - cloud.google.com/go/iam v1.4.1 // indirect - cloud.google.com/go/kms v1.21.0 // indirect - cloud.google.com/go/longrunning v0.6.6 // indirect - cloud.google.com/go/security v1.18.4 // indirect - dario.cat/mergo v1.0.1 // indirect - filippo.io/edwards25519 v1.1.0 // indirect - github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect - github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.3.0 // indirect - github.com/Masterminds/sprig/v3 v3.3.0 // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ThalesIgnite/crypto11 v1.2.5 // indirect + github.com/Knetic/govaluate v3.0.1-0.20250325060307-7625b7f8c03d+incompatible // indirect github.com/a8m/envsubst v1.4.2 // indirect github.com/arthurnn/twirp-ruby v1.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/aws/aws-sdk-go v1.51.8 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.6 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.59 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.37.18 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 // indirect - github.com/aws/smithy-go v1.22.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bitly/go-simplejson v0.5.1 // indirect - github.com/boombuler/barcode v1.0.1 // indirect github.com/bsm/redislock v0.9.4 // indirect - github.com/caddyserver/zerossl v0.1.3 // indirect - github.com/ccoveille/go-safecast v1.6.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/chzyer/readline v1.5.1 // indirect github.com/coreos/go-oidc/v3 v3.13.0 // indirect github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.7.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect - github.com/dgraph-io/badger v1.6.2 // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect - github.com/go-chi/chi/v5 v5.2.1 // indirect github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-piv/piv-go/v2 v2.3.0 // indirect - github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/goccy/go-json v0.10.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect - github.com/golang/glog v1.2.4 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.3 // indirect - github.com/google/certificate-transparency-go v1.2.2 // indirect github.com/google/go-tpm v0.9.3 // indirect - github.com/google/go-tpm-tools v0.4.5 // indirect - github.com/google/go-tspi v0.3.0 // indirect - github.com/google/jsonapi v1.0.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect - github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/api v1.16.0 // indirect - github.com/hashicorp/vault/api/auth/approle v0.9.0 // indirect - github.com/hashicorp/vault/api/auth/aws v0.9.0 // indirect - github.com/hashicorp/vault/api/auth/kubernetes v0.9.0 // indirect - github.com/huandu/xstrings v1.5.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.6.0 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect github.com/justinas/alice v1.2.0 // indirect github.com/klauspost/compress v1.18.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect - github.com/lestrrat-go/blackmagic v1.0.2 // indirect + github.com/lestrrat-go/blackmagic v1.0.3 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/httprc/v3 v3.0.0-beta1 // indirect + github.com/lestrrat-go/httprc/v3 v3.0.0-beta2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect - github.com/libdns/libdns v0.2.3 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/manifoldco/promptui v0.9.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa // indirect - github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect - github.com/mholt/acmez/v3 v3.1.1 // indirect - github.com/miekg/dns v1.1.63 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect github.com/minio/highwayhash v1.0.3 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/jwt/v2 v2.7.3 // indirect github.com/nats-io/nats-server/v2 v2.11.1-0.20250328102232-bfb8894825bc // indirect github.com/nats-io/nkeys v0.4.10 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/newrelic/go-agent/v3 v3.37.0 // indirect github.com/oauth2-proxy/oauth2-proxy/v7 v7.8.2 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/peterbourgon/diskv/v3 v3.0.1 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/playwright-community/playwright-go v0.5001.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/pquerna/otp v1.4.0 // indirect github.com/prometheus/client_golang v1.21.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/redis/go-redis/v9 v9.7.3 // indirect - github.com/rs/xid v1.6.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/schollz/jsonstore v1.1.0 // indirect github.com/segmentio/asm v1.2.0 // indirect - github.com/shopspring/decimal v1.4.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/slackhq/nebula v1.9.5 // indirect - github.com/smallstep/certificates v0.28.3 // indirect - github.com/smallstep/certinfo v1.13.0 // indirect - github.com/smallstep/cli v0.28.6 // indirect - github.com/smallstep/cli-utils v0.12.1 // indirect - github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 // indirect - github.com/smallstep/linkedca v0.23.0 // indirect - github.com/smallstep/nosql v0.7.0 // indirect - github.com/smallstep/pkcs7 v0.2.1 // indirect - github.com/smallstep/scep v0.0.0-20240926084937-8cf1ca453101 // indirect - github.com/smallstep/truststore v0.13.0 // indirect - github.com/smallstep/zcrypto v0.0.0-20221001003018-1ab2364d2a91 // indirect - github.com/smallstep/zlint v0.0.0-20220930192201-67fb4aa21910 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/thales-e-security/pool v0.0.2 // indirect - github.com/twitchtv/twirp v8.1.3+incompatible // indirect - github.com/urfave/cli v1.22.16 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/weppos/publicsuffix-go v0.20.0 // indirect - github.com/x448/float16 v0.8.4 // indirect - github.com/zeebo/blake3 v0.2.4 // indirect - go.etcd.io/bbolt v1.3.11 // indirect - go.mozilla.org/pkcs7 v0.9.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect go.opentelemetry.io/otel v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel/trace v1.34.0 // indirect - go.step.sm/crypto v0.59.1 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/mod v0.24.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/net v0.37.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.31.0 // indirect google.golang.org/api v0.228.0 // indirect - google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect @@ -244,10 +113,7 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - howett.net/plist v1.0.0 // indirect k8s.io/apimachinery v0.32.3 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - software.sslmate.com/src/go-pkcs12 v0.5.0 // indirect ) tool ( @@ -256,8 +122,6 @@ tool ( github.com/nats-io/nats-server/v2 github.com/oauth2-proxy/oauth2-proxy/v7 github.com/playwright-community/playwright-go/cmd/playwright - github.com/smallstep/certificates/cmd/step-ca - github.com/smallstep/cli/cmd/step github.com/twitchtv/twirp/protoc-gen-twirp google.golang.org/grpc/cmd/protoc-gen-go-grpc google.golang.org/protobuf/cmd/protoc-gen-go @@ -1,59 +1,15 @@ -cloud.google.com/go v0.118.3 h1:jsypSnrE/w4mJysioGdMBg4MiW/hHx/sArFpaBWHdME= -cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc= cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps= cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/iam v1.4.1 h1:cFC25Nv+u5BkTR/BT1tXdoF2daiVbZ1RLx2eqfQ9RMM= -cloud.google.com/go/iam v1.4.1/go.mod h1:2vUEJpUG3Q9p2UdsyksaKpDzlwOrnMzS30isdReIcLM= -cloud.google.com/go/kms v1.21.0 h1:x3EeWKuYwdlo2HLse/876ZrKjk2L5r7Uexfm8+p6mSI= -cloud.google.com/go/kms v1.21.0/go.mod h1:zoFXMhVVK7lQ3JC9xmhHMoQhnjEDZFoLAr5YMwzBLtk= -cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw= -cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= -cloud.google.com/go/security v1.18.4 h1:vY/Z2D+bE9PqdZNiPpW+RLSzDNDVWkNDFKdCnqOeCis= -cloud.google.com/go/security v1.18.4/go.mod h1:+oNVB34sloqG2K3IpoT2KUDgNAbAJ9A2uENjAUvgzRQ= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= -github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= -github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= -github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= -github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= -github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= -github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= +github.com/Knetic/govaluate v3.0.1-0.20250325060307-7625b7f8c03d+incompatible h1:PQkGQvISFXAw+Lkmcyd5OUGDVtdQdY1u0CIDjDbBg64= +github.com/Knetic/govaluate v3.0.1-0.20250325060307-7625b7f8c03d+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= @@ -62,99 +18,35 @@ github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQg github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op h1:+OSa/t11TFhqfrX0EOSqQBDJ0YlpmK0rDSiB19dg9M0= github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/arthurnn/twirp-ruby v1.13.0 h1:j0T7I5oxe2niKFdfjiiCmkiydwYeegrbwVMs+Gajm6M= github.com/arthurnn/twirp-ruby v1.13.0/go.mod h1:1fVOQuSLzwXoPi9/ejlDYG3roilJIPAZN2sw+A3o48o= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.51.8 h1:tD7gQq5XKuKdhA6UMEH26ZNQH0s+HbL95rzv/ACz5TQ= -github.com/aws/aws-sdk-go v1.51.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBWM5E= -github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= -github.com/aws/aws-sdk-go-v2/config v1.29.6 h1:fqgqEKK5HaZVWLQoLiC9Q+xDlSp+1LYidp6ybGE2OGg= -github.com/aws/aws-sdk-go-v2/config v1.29.6/go.mod h1:Ft+WLODzDQmCTHDvqAH1JfC2xxbZ0MxpZAcJqmE1LTQ= -github.com/aws/aws-sdk-go-v2/credentials v1.17.59 h1:9btwmrt//Q6JcSdgJOLI98sdr5p7tssS9yAsGe8aKP4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.59/go.mod h1:NM8fM6ovI3zak23UISdWidyZuI1ghNe2xjzUZAyT+08= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 h1:BjUcr3X3K0wZPGFg2bxOWW3VPN8rkE3/61zhP+IHviA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32/go.mod h1:80+OGC/bgzzFFTUmcuwD0lb4YutwQeKLFpmt6hoWapU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 h1:m1GeXHVMJsRsUAqG6HjZWx9dj7F5TR+cF1bjyfYyBd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32/go.mod h1:IitoQxGfaKdVLNg0hD8/DXmAqNy0H4K2H2Sf91ti8sI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE= -github.com/aws/aws-sdk-go-v2/service/kms v1.37.18 h1:pi9M/9n1PLayBXjia7LfwgXwcpFdFO7Q2cqKOZa1ZmM= -github.com/aws/aws-sdk-go-v2/service/kms v1.37.18/go.mod h1:vZXvmzfhdsPj/axc8+qk/2fSCP4hGyaZ1MAduWEHAxM= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14/go.mod h1:RVwIw3y/IqxC2YEXSIkAzRDdEU1iRabDPaYjpGCbCGQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 h1:TzeR06UCMUq+KA3bDkujxK1GVGy+G8qQN/QVYzGLkQE= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98wpaTeqt5+DMidZD0A9BYTizc= -github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= -github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow= github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw= github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk= -github.com/caddyserver/certmagic v0.22.2 h1:qzZURXlrxwR5m25/jpvVeEyJHeJJMvAwe5zlMufOTQk= -github.com/caddyserver/certmagic v0.22.2/go.mod h1:hbqE7BnkjhX5IJiFslPmrSeobSeZvI6ux8tyxhsd6qs= -github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= -github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/casbin/casbin/v3 v3.0.0-beta.7 h1:siS3e6cRtuyFlshUgJfw0wnWuK3z3U/ald0C8Jtof24= github.com/casbin/casbin/v3 v3.0.0-beta.7/go.mod h1:69HoI+h4yMUTydUMxT7VQh7FgGpoJsB/ZskkVGcvasQ= -github.com/ccoveille/go-safecast v1.6.0 h1:kxc0VIsdEaYoKZbDiGBZBV62zAp0RdtFNH6E3Krev8s= -github.com/ccoveille/go-safecast v1.6.0/go.mod h1:QqwNjxQ7DAqY0C721OIO9InMk9zCwcsO7tnRuHytad8= github.com/cedar-policy/cedar-go v1.1.1 h1:yXCEaYQCXC+BxbOx/8TDHQu4dfuWVLs8irGrGjqClu0= github.com/cedar-policy/cedar-go v1.1.1/go.mod h1:pEgiK479O5dJfzXnTguOMm+bCplzy5rEEFPGdZKPWz4= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cedar-policy/cedar-go v1.2.1 h1:f4Ie1j6OT2TqtmnbVcR7OyJWfyPEUvYrFYaurQZhTAo= +github.com/cedar-policy/cedar-go v1.2.1/go.mod h1:Ahhlu3DxDzvGTR88v/+j/EeiMEyvta11hlkdDgj4AZU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc/v3 v3.13.0 h1:M66zd0pcc5VxvBNM4pB331Wrsanby+QomQYjN8HamW8= github.com/coreos/go-oidc/v3 v3.13.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -163,39 +55,16 @@ github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusg github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= -github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= -github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= -github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= -github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= @@ -205,59 +74,26 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-piv/piv-go/v2 v2.3.0 h1:kKkrYlgLQTMPA6BiSL25A7/x4CEh2YCG7rtb/aTkx+g= -github.com/go-piv/piv-go/v2 v2.3.0/go.mod h1:ShZi74nnrWNQEdWzRUd/3cSig3uNOcEZp+EWl0oewnI= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc= -github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= -github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.2.2 h1:5TAzjQnCfN1vps2XWUgU6Svt++rgy9a+b8CBYXaKUAo= -github.com/google/certificate-transparency-go v1.2.2/go.mod h1:d1o5XNQzK/yz8IXzEce6KXgMxfter/EcMP9vG4dBRNE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-configfs-tsm v0.3.3-0.20240919001351-b4b5b84fdcbc h1:SG12DWUUM5igxm+//YX5Yq4vhdoRnOG9HkCodkOn+YU= -github.com/google/go-configfs-tsm v0.3.3-0.20240919001351-b4b5b84fdcbc/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-sev-guest v0.12.1 h1:H4rFYnPIn8HtqEsNTmh56Zxcf9BI9n48ZSYCnpYLYvc= -github.com/google/go-sev-guest v0.12.1/go.mod h1:SK9vW+uyfuzYdVN0m8BShL3OQCtXZe/JPF7ZkpD3760= -github.com/google/go-tdx-guest v0.3.2-0.20241009005452-097ee70d0843 h1:+MoPobRN9HrDhGyn6HnF5NYo4uMBKaiFqAtf/D/OB4A= -github.com/google/go-tdx-guest v0.3.2-0.20241009005452-097ee70d0843/go.mod h1:g/n8sKITIT9xRivBUbizo34DTsUm2nN2uU3A662h09g= github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc= github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= -github.com/google/go-tpm-tools v0.4.5 h1:3fhthtyMDbIZFR5/0y1hvUoZ1Kf4i1eZ7C73R4Pvd+k= -github.com/google/go-tpm-tools v0.4.5/go.mod h1:ktjTNq8yZFD6TzdBFefUfen96rF3NpYwpSb2d8bc+Y8= -github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= -github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= github.com/google/jsonapi v1.0.0 h1:qIGgO5Smu3yJmSs+QlvhQnrscdZfFhiV6S8ryJAglqU= github.com/google/jsonapi v1.0.0/go.mod h1:YYHiRPJT8ARXGER8In9VuLv4qvLfDmA9ULQqptbLE4s= -github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= -github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= @@ -270,141 +106,54 @@ github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrk github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= -github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 h1:W9WN8p6moV1fjKLkeqEgkAMu5rauy9QeYDAmIaPuuiA= -github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= -github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= -github.com/hashicorp/vault/api/auth/approle v0.9.0 h1:FdpspwGVWnGiWmAxd5L1Yd+T+fX2kYnyAIvI5oGdvNs= -github.com/hashicorp/vault/api/auth/approle v0.9.0/go.mod h1:fvtJhBs3AYMs2fXk4U5+u+7unhUGuboiKzFpLPpIazw= -github.com/hashicorp/vault/api/auth/aws v0.9.0 h1:XtV/fRhgf/MaPv5SLBgXf+Yn/QGjFYIlJkdcPktDlbc= -github.com/hashicorp/vault/api/auth/aws v0.9.0/go.mod h1:DvUmnZg9T+HGYdkagNMCssdgbt9ODAyBjllY8PpaMvM= -github.com/hashicorp/vault/api/auth/kubernetes v0.9.0 h1:xV3xXMtSV8tq5iefueAw3OOdhhXyjnyhrQkIFM5fh54= -github.com/hashicorp/vault/api/auth/kubernetes v0.9.0/go.mod h1:3K6uEUKZLBQ3d+eXAa4Ubp4UocswU90zY4QP5Az3Vw8= -github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= -github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= -github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= -github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= -github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs= +github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc/v3 v3.0.0-beta1 h1:pzDjP9dSONCFQC/AE3mWUnHILGiYPiMKzQIS+weKJXA= github.com/lestrrat-go/httprc/v3 v3.0.0-beta1/go.mod h1:wdsgouffPvWPEYh8t7PRH/PidR5sfVqt0na4Nhj60Ms= +github.com/lestrrat-go/httprc/v3 v3.0.0-beta2 h1:SDxjGoH7qj0nBXVrcrxX8eD94wEnjR+EEuqqmeqQYlY= +github.com/lestrrat-go/httprc/v3 v3.0.0-beta2/go.mod h1:Nwo81sMxE0DcvTB+rJyynNhv/DUu2yZErV7sscw9pHE= github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3 h1:HHT8iW+UcPBgBr5A3soZQQsL5cBor/u6BkLB+wzY/R0= github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3/go.mod h1:ak32WoNtHE0aLowVWBcCvXngcAnW4tuC0YhFwOr/kwc= +github.com/lestrrat-go/jwx/v3 v3.0.1 h1:fH3T748FCMbXoF9UXXNS9i0q6PpYyJZK/rKSbkt2guY= +github.com/lestrrat-go/jwx/v3 v3.0.1/go.mod h1:XP2WqxMOSzHSyf3pfibCcfsLqbomxakAnNqiuaH8nwo= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8= -github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= -github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa h1:hI1uC2A3vJFjwvBn0G0a7QBRdBUp6Y048BtLAHRTKPo= github.com/mbland/hmacauth v0.0.0-20170912233209-44256dfd4bfa/go.mod h1:8vxFeeg++MqgCHwehSuwTlYCF0ALyDJbYJ1JsKi7v6s= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= -github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mholt/acmez/v3 v3.1.1 h1:Jh+9uKHkPxUJdxM16q5mOr+G2V0aqkuFtNA28ihCxhQ= -github.com/mholt/acmez/v3 v3.1.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= -github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= -github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= -github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/jwt/v2 v2.7.3 h1:6bNPK+FXgBeAqdj4cYQ0F8ViHRbi7woQLq4W29nUAzE= @@ -417,8 +166,6 @@ github.com/nats-io/nkeys v0.4.10 h1:glmRrpCmYLHByYcePvnTBEAwawwapjCPMjy2huw20wc= github.com/nats-io/nkeys v0.4.10/go.mod h1:OjRrnIKnWBFl+s4YK5ChQfvHP2fxqZexrKJoVVyWB3U= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/newrelic/go-agent/v3 v3.37.0 h1:vAidwr7gUThxT+NvxDG3qUxgeuJbzxhYAEeiKtPn/ig= -github.com/newrelic/go-agent/v3 v3.37.0/go.mod h1:4QXvru0vVy/iu7mfkNHT7T2+9TC9zPGO8aUEdKqY138= github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25 h1:9bCMuD3TcnjeqjPT2gSlha4asp8NvgcFRYExCaikCxk= github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25/go.mod h1:eDjgYHYDJbPLBLsyZ6qRaugP0mX8vePOhZ5id1fdzJw= github.com/oauth2-proxy/oauth2-proxy/v7 v7.8.2 h1:V401AcLfoQsX9s5iCD+/V/X0H+pNXwFxSLlPxUSr4c8= @@ -427,16 +174,10 @@ github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0 github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU= -github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/playwright-community/playwright-go v0.5001.0 h1:EY3oB+rU9cUp6CLHguWE8VMZTwAg+83Yyb7dQqEmGLg= @@ -444,9 +185,6 @@ github.com/playwright-community/playwright-go v0.5001.0/go.mod h1:kBNWs/w2aJ2ZUp github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= -github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= @@ -459,133 +197,48 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/schollz/jsonstore v1.1.0 h1:WZBDjgezFS34CHI+myb4s8GGpir3UMpy7vWoCeO0n6E= -github.com/schollz/jsonstore v1.1.0/go.mod h1:15c6+9guw8vDRyozGjN3FoILt0wpruJk9Pi66vjaZfg= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/slackhq/nebula v1.9.5 h1:ZrxcvP/lxwFglaijmiwXLuCSkybZMJnqSYI1S8DtGnY= -github.com/slackhq/nebula v1.9.5/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smallstep/certificates v0.28.3 h1:rcMh1TAs8m2emP3aDJxKLkE9jriAtcFtCuj2gttnpmI= -github.com/smallstep/certificates v0.28.3/go.mod h1:P/IjGTvRCem3YZ7d1XtUxpvK/8dfFsJn7gaVLpMXbJw= -github.com/smallstep/certinfo v1.13.0 h1:iv/Fc1c8vke1asJZI7s3XoH7Wo/MY7znK0TlDUsSAhs= -github.com/smallstep/certinfo v1.13.0/go.mod h1:2pGT3T7r0s5f3BpJRi/j5K5akgvL3RfYXts5rDICkEA= -github.com/smallstep/cli v0.28.6 h1:gjR8MNWI0f8YWesSoeFmGR3EbqnPWZcsy14GINe4Pwo= -github.com/smallstep/cli v0.28.6/go.mod h1:3CBca5nOW1CbZzKqh8WfMHjpqvX4hQGowoY2G9lEkdY= -github.com/smallstep/cli-utils v0.12.1 h1:D9QvfbFqiKq3snGZ2xDcXEFrdFJ1mQfPHZMq/leerpE= -github.com/smallstep/cli-utils v0.12.1/go.mod h1:skV2Neg8qjiKPu2fphM89H9bIxNpKiiRTnX9Q6Lc+20= -github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA= -github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4= -github.com/smallstep/linkedca v0.23.0 h1:5W/7EudlK1HcCIdZM68dJlZ7orqCCCyv6bm2l/0JmLU= -github.com/smallstep/linkedca v0.23.0/go.mod h1:7cyRM9soAYySg9ag65QwytcgGOM+4gOlkJ/YA58A9E8= -github.com/smallstep/nosql v0.7.0 h1:YiWC9ZAHcrLCrayfaF+QJUv16I2bZ7KdLC3RpJcnAnE= -github.com/smallstep/nosql v0.7.0/go.mod h1:H5VnKMCbeq9QA6SRY5iqPylfxLfYcLwvUff3onQ8+HU= -github.com/smallstep/pkcs7 v0.0.0-20240911091500-b1cae6277023/go.mod h1:CM5KrX7rxWgwDdMj9yef/pJB2OPgy/56z4IEx2UIbpc= -github.com/smallstep/pkcs7 v0.2.1 h1:6Kfzr/QizdIuB6LSv8y1LJdZ3aPSfTNhTLqAx9CTLfA= -github.com/smallstep/pkcs7 v0.2.1/go.mod h1:RcXHsMfL+BzH8tRhmrF1NkkpebKpq3JEM66cOFxanf0= -github.com/smallstep/scep v0.0.0-20240926084937-8cf1ca453101 h1:LyZqn24/ZiVg8v9Hq07K6mx6RqPtpDeK+De5vf4QEY4= -github.com/smallstep/scep v0.0.0-20240926084937-8cf1ca453101/go.mod h1:EuKQjYGQwhUa1mgD21zxIgOgUYLsqikJmvxNscxpS/Y= -github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4= -github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A= -github.com/smallstep/zcrypto v0.0.0-20221001003018-1ab2364d2a91 h1:XE0cgVBMkYPxOZv4F3YY5mX9GgentifWU6vyJb6gKmc= -github.com/smallstep/zcrypto v0.0.0-20221001003018-1ab2364d2a91/go.mod h1:9AA5+s5DF+8sE93nQ7HUalesU2SDqNfvrwn+dls9upw= -github.com/smallstep/zlint v0.0.0-20220930192201-67fb4aa21910 h1:eIjaqvVEq+8eWaZd56yA7Ux5W6gJ9kqvq9ZWTsp3fkc= -github.com/smallstep/zlint v0.0.0-20220930192201-67fb4aa21910/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= -github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJXP61mNV3/7iuU= github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= -github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/weppos/publicsuffix-go v0.12.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/weppos/publicsuffix-go v0.20.0 h1:59ypvSUbW3Dunc6zVm+v+MmXf2Q6cGiNDkxgRIzEnaA= -github.com/weppos/publicsuffix-go v0.20.0/go.mod h1:5ZC/Uv3fIEUE0eP6o9+Yg4+5+W8V0/BieMi05feGXVA= -github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220704091424-e0182326a282/go.mod h1:GHfoeIdZLdZmLjMlzBftbTDntahTttUMWjxZwQJhULE= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlgmokha/x v0.0.0-20250404223908-0b29f54f06e7 h1:Jjik5MGVznsXlo+otZXsWuKvbg3lCixMEIIkoxx0Ojc= github.com/xlgmokha/x v0.0.0-20250404223908-0b29f54f06e7/go.mod h1:kLXa5uHaL3VF9ly6XlioU/Q1gittXvAYh6s1WpOFaU8= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xlgmokha/x v0.0.0-20250430185455-b691eda27477 h1:oeKrn9BSDSic5MTXKhQesxhIhB7byxl86IHtCD+yw4k= +github.com/xlgmokha/x v0.0.0-20250430185455-b691eda27477/go.mod h1:axGPKzoJCNTmPJxYqN5l+Z9gGbPe0yolkT61a5p3QiI= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= -github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= -github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= -github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= -go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= -go.mozilla.org/pkcs7 v0.9.0 h1:yM4/HS9dYv7ri2biPtxt8ikvB37a980dg69/pKmS+eI= -go.mozilla.org/pkcs7 v0.9.0/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= @@ -602,48 +255,28 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= -go.step.sm/crypto v0.59.1 h1:jUL+5p19YS9YJKLaPUgkS2OdGm7s0+hwP7AqTFyF9Cg= -go.step.sm/crypto v0.59.1/go.mod h1:XHavmnzfTyPpQE/n4YokEtjiBzP3LZI9/1O061f5y0o= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= -go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= @@ -651,85 +284,52 @@ golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs= google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4= -google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE= -google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= @@ -741,28 +341,17 @@ google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zt google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= -howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M= -software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/lib/.keep b/lib/.keep deleted file mode 100644 index e69de29b..00000000 --- a/lib/.keep +++ /dev/null diff --git a/lib/authx.rb b/lib/authx.rb deleted file mode 100644 index 5ee3f543..00000000 --- a/lib/authx.rb +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -require "authx/rpc" - -module Authx -end diff --git a/lib/authx/rpc.rb b/lib/authx/rpc.rb deleted file mode 100644 index 78edbc46..00000000 --- a/lib/authx/rpc.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -require "authx/rpc/ability_pb" -require "authx/rpc/ability_twirp" diff --git a/lib/authx/rpc/ability_pb.rb b/lib/authx/rpc/ability_pb.rb deleted file mode 100644 index ee71dc57..00000000 --- a/lib/authx/rpc/ability_pb.rb +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: ability.proto - -require 'google/protobuf' - -Google::Protobuf::DescriptorPool.generated_pool.build do - add_file("ability.proto", :syntax => :proto3) do - add_message "authx.rpc.AllowRequest" do - optional :subject, :string, 1 - optional :permission, :string, 2 - optional :resource, :string, 3 - end - add_message "authx.rpc.AllowReply" do - optional :result, :bool, 1 - end - end -end - -module Authx - module Rpc - AllowRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("authx.rpc.AllowRequest").msgclass - AllowReply = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("authx.rpc.AllowReply").msgclass - end -end diff --git a/lib/authx/rpc/ability_twirp.rb b/lib/authx/rpc/ability_twirp.rb deleted file mode 100644 index 120e9a99..00000000 --- a/lib/authx/rpc/ability_twirp.rb +++ /dev/null @@ -1,17 +0,0 @@ -# Code generated by protoc-gen-twirp_ruby 1.11.0, DO NOT EDIT. -require 'twirp' -require_relative 'ability_pb.rb' - -module Authx - module Rpc - class AbilityService < ::Twirp::Service - package 'authx.rpc' - service 'Ability' - rpc :Allowed, AllowRequest, AllowReply, :ruby_method => :allowed - end - - class AbilityClient < ::Twirp::Client - client_for AbilityService - end - end -end diff --git a/magefiles/magefile.go b/magefiles/magefile.go index 71aa3bc8..06dc0251 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -16,49 +16,10 @@ import ( // If not set, running mage will list available targets var Default = Servers -// Run the Identity Provider -func Idp() error { - env := map[string]string{ - "SCHEME": "http", - "PORT": "8282", - "HOST": "idp.example.com:8080", - } - return sh.RunWithV(env, "ruby", "./bin/idp") -} - -// Run the UI (a.k.a Service Provider) -func UI() error { - env := map[string]string{ - "SCHEME": "http", - "PORT": "8283", - "HOST": "ui.example.com:8080", - "IDP_HOST": "idp.example.com:8080", - } - return sh.RunWithV(env, "ruby", "./bin/ui") -} - -// Run the API Gateway -func Gateway() error { - env := map[string]string{ - "BIND_ADDR": ":8080", - } - return sh.RunWithV(env, "go", "run", "./cmd/gtwy/main.go") -} - -// Run the REST API -func Api() error { - env := map[string]string{ - "SCHEME": "http", - "PORT": "8284", - "HOST": "localhost:8284", - } - return sh.RunWithV(env, "ruby", "./bin/api") -} - // Run the Authzd Service func Authzd() error { env := map[string]string{ - "BIND_ADDR": ":50051", + "BIND_ADDR": ":8080", } return sh.RunWithV(env, "go", "run", "./cmd/authzd/main.go") } @@ -82,13 +43,8 @@ func Protos() error { if err := sh.RunV( "protoc", "--proto_path=./protos", - "--go_out=pkg/rpc", - "--go_opt=paths=source_relative", - "--go-grpc_out=pkg/rpc", - "--go-grpc_opt=paths=source_relative", - "--twirp_out=pkg/rpc", - "--ruby_out=lib/authx/rpc", - "--twirp_ruby_out=lib/authx/rpc", + "--go_out=.", + "--twirp_out=.", file, ); err != nil { return err @@ -100,7 +56,7 @@ func Protos() error { // Run All the servers func Servers(ctx context.Context) { - mg.CtxDeps(ctx, (Step{}).Server, Nats, Idp, UI, Api, Authzd, Gateway) + mg.CtxDeps(ctx, Nats, Authzd) } // Run the end to end tests diff --git a/magefiles/step.go b/magefiles/step.go deleted file mode 100644 index 25cf23b0..00000000 --- a/magefiles/step.go +++ /dev/null @@ -1,147 +0,0 @@ -//go:build mage -// +build mage - -package main - -import ( - "context" - "encoding/json" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/magefile/mage/mg" - "github.com/magefile/mage/sh" - "github.com/magefile/mage/target" - "github.com/xlgmokha/x/pkg/env" - "github.com/xlgmokha/x/pkg/x" -) - -type Step mg.Namespace - -func (s Step) Clean() error { - globs := []string{ - "tmp/step/*/*", - } - for _, item := range globs { - fs, err := filepath.Glob(item) - if err != nil { - return err - } - for _, f := range fs { - if strings.HasSuffix(f, "/.keep") { - continue - } - if err := os.RemoveAll(f); err != nil { - return err - } - } - } - return nil -} - -func (s Step) Setup() { - mg.SerialDeps(s.mkPassword, s.createCA, s.enableACMEProvisioner) -} - -func (s Step) Install() error { - return sh.RunWithV( - s.env(), - "step", - "certificate", - "install", - s.pathPlus("/certs/root_ca.crt"), - ) -} - -func (s Step) Server(ctx context.Context) error { - mg.SerialDeps(s.Setup) - - return sh.RunWithV( - s.env(), - "step-ca", - s.pathPlus("config/ca.json"), - "--password-file="+s.pathPlus("password.txt"), - ) -} - -func (s Step) Provisioners() error { - return sh.RunV("curl", "-k", "-s", "https://localhost:8081/provisioners") -} - -func (s Step) ACME() error { - return sh.RunV("curl", "-k", "-s", "https://localhost:8081/acme/acme/directory") -} - -func (s Step) Status() { - mg.SerialDeps(s.Provisioners, s.ACME) -} - -func (s Step) mkPassword() error { - file := s.passwordFile() - if ok, err := target.Dir(file); err != nil || !ok { - return nil - } - - return os.WriteFile(file, []byte("password"), 0600) -} - -func (s Step) createCA() error { - if ok, err := target.Dir(s.pathPlus("config/ca.json"), s.passwordFile()); err != nil || !ok { - return nil - } - - return sh.RunWithV( - s.env(), - "step", - "ca", - "init", - "--deployment-type=standalone", - "--address=localhost:8081", - "--dns=localhost", - "--dns=*.localhost", - "--name=CA", - "--provisioner=example", - "--provisioner-password-file="+s.passwordFile(), - "--password-file="+s.passwordFile(), - ) -} - -func (s Step) enableACMEProvisioner() error { - bytes, err := ioutil.ReadFile(s.pathPlus("config/ca.json")) - if err != nil { - return err - } - - items := map[string]interface{}{} - if err := json.Unmarshal(bytes, &items); err != nil { - return err - } - - provisioners := items["authority"].(map[string]interface{})["provisioners"].([]interface{}) - if len(provisioners) < 2 { - return sh.RunWithV(s.env(), "step", "ca", "provisioner", "add", "acme", "--type", "ACME") - } - return nil -} - -func (step Step) passwordFile() string { - return step.pathPlus("password.txt") -} - -func (s Step) path() string { - return env.Fetch("STEPPATH", filepath.Join(x.Must(os.Getwd()), "/tmp/step")) -} - -func (s Step) env() map[string]string { - return map[string]string{ - "STEPPATH": s.path(), - "HOST": "localhost", - "PORT": "8081", - } -} - -func (s Step) pathPlus(path string) string { - return filepath.Join(s.path(), path) -} diff --git a/pkg/app/app.go b/pkg/app/app.go deleted file mode 100644 index 89a2bd34..00000000 --- a/pkg/app/app.go +++ /dev/null @@ -1,25 +0,0 @@ -package app - -import ( - "os" - - "github.com/xlgmokha/x/pkg/log" - "gitlab.com/mokhax/spike/pkg/authz" - "gitlab.com/mokhax/spike/pkg/cfg" - "gitlab.com/mokhax/spike/pkg/srv" -) - -func Start(bindAddr string) error { - logger := log.New(os.Stdout, log.Fields{"app": "gtwy"}) - mux := authz.HTTP(authz.WithCasbin(), Routes()) - return srv.Run(cfg.New( - bindAddr, - cfg.WithMux(log.HTTP(logger)(mux)), - cfg.WithTLS([]string{ - "api.example.com", - "authzd.example.com", - "idp.example.com", - "ui.example.com", - }), - )) -} diff --git a/pkg/app/routes.go b/pkg/app/routes.go deleted file mode 100644 index ff1291c2..00000000 --- a/pkg/app/routes.go +++ /dev/null @@ -1,18 +0,0 @@ -package app - -import ( - "net/http" - - "gitlab.com/mokhax/spike/pkg/prxy" -) - -func Routes() http.Handler { - mux := http.NewServeMux() - mux.Handle("/", prxy.New(map[string]string{ - "api.example.com": "http://localhost:8284", - "authzd.example.com": "http://localhost:50051", - "idp.example.com": "http://localhost:8282", - "ui.example.com": "http://localhost:8283", - })) - return mux -} diff --git a/pkg/authz/authz.go b/pkg/authz/authz.go deleted file mode 100644 index 5a93a29c..00000000 --- a/pkg/authz/authz.go +++ /dev/null @@ -1,23 +0,0 @@ -package authz - -import "net/http" - -type Authorizer interface { - Authorize(*http.Request) bool -} - -type AuthorizerFunc func(*http.Request) bool - -func (f AuthorizerFunc) Authorize(r *http.Request) bool { - return f(r) -} - -func HTTP(authorizer Authorizer, h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if authorizer.Authorize(r) { - h.ServeHTTP(w, r) - } else { - w.WriteHeader(http.StatusForbidden) - } - }) -} diff --git a/pkg/authz/casbin.go b/pkg/authz/casbin.go deleted file mode 100644 index 140bdb98..00000000 --- a/pkg/authz/casbin.go +++ /dev/null @@ -1,43 +0,0 @@ -package authz - -import ( - "fmt" - "net" - "net/http" - - "github.com/casbin/casbin/v3" - "github.com/xlgmokha/x/pkg/log" - "github.com/xlgmokha/x/pkg/x" -) - -func WithCasbin() Authorizer { - enforcer := x.Must(casbin.NewEnforcer("casbin.conf", "casbin.csv")) - - return AuthorizerFunc(func(r *http.Request) bool { - host, _, err := net.SplitHostPort(r.Host) - if err != nil { - log.WithFields(r.Context(), log.Fields{"error": err}) - return false - } - - subject, found := TokenFrom(r).Subject() - if !found { - subject = "*" - } - ok, err := enforcer.Enforce(subject, host, r.Method, r.URL.Path) - if err != nil { - log.WithFields(r.Context(), log.Fields{"error": err}) - return false - } - - fmt.Printf("%v: %v -> %v %v%v\n", ok, subject, r.Method, host, r.URL.Path) - log.WithFields(r.Context(), log.Fields{ - "authz": ok, - "subject": subject, - "action": r.Method, - "domain": host, - "object": r.URL.Path, - }) - return ok - }) -} diff --git a/pkg/authz/cedar.go b/pkg/authz/cedar.go deleted file mode 100644 index 18674c74..00000000 --- a/pkg/authz/cedar.go +++ /dev/null @@ -1,34 +0,0 @@ -package authz - -import ( - "net" - "net/http" - - cedar "github.com/cedar-policy/cedar-go" - "github.com/xlgmokha/x/pkg/log" - "gitlab.com/mokhax/spike/pkg/gid" - "gitlab.com/mokhax/spike/pkg/policies" -) - -func WithCedar() Authorizer { - return AuthorizerFunc(func(r *http.Request) bool { - host, _, err := net.SplitHostPort(r.Host) - if err != nil { - log.WithFields(r.Context(), log.Fields{"error": err}) - return false - } - subject, found := TokenFrom(r).Subject() - if !found { - subject = "gid://example/User/*" - } - - return policies.Allowed(cedar.Request{ - Principal: gid.NewEntityUID(subject), - Action: cedar.NewEntityUID("HttpMethod", cedar.String(r.Method)), - Resource: cedar.NewEntityUID("HttpPath", cedar.String(r.URL.Path)), - Context: cedar.NewRecord(cedar.RecordMap{ - "host": cedar.String(host), - }), - }) - }) -} diff --git a/pkg/authz/token.go b/pkg/authz/token.go deleted file mode 100644 index 2794bf4a..00000000 --- a/pkg/authz/token.go +++ /dev/null @@ -1,30 +0,0 @@ -package authz - -import ( - "net/http" - "strings" - - "github.com/lestrrat-go/jwx/v3/jwt" - "github.com/xlgmokha/x/pkg/log" -) - -func TokenFrom(r *http.Request) jwt.Token { - authorization := r.Header.Get("Authorization") - if authorization == "" || !strings.Contains(authorization, "Bearer") { - return jwt.New() - } - - token, err := jwt.ParseRequest(r, - jwt.WithContext(r.Context()), - jwt.WithHeaderKey("Authorization"), - jwt.WithValidate(false), // TODO:: Connect this to a JSON Web Key Set - jwt.WithVerify(false), // TODO:: Connect this to a JSON Web Key Set - ) - - if err != nil { - log.WithFields(r.Context(), log.Fields{"error": err}) - return jwt.New() - } - - return token -} diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go deleted file mode 100644 index 0d7a6427..00000000 --- a/pkg/cfg/cfg.go +++ /dev/null @@ -1,34 +0,0 @@ -package cfg - -import ( - "crypto/tls" - "net/http" -) - -type Config struct { - BindAddress string - Mux http.Handler - TLS *tls.Config -} - -func New(addr string, options ...Option) *Config { - if addr == "" { - addr = ":0" - } - - c := &Config{ - BindAddress: addr, - Mux: http.DefaultServeMux, - } - for _, option := range options { - option(c) - } - return c -} - -func (c *Config) Run(server *http.Server) error { - if c.TLS != nil { - return server.ListenAndServeTLS("", "") - } - return server.ListenAndServe() -} diff --git a/pkg/cfg/mux.go b/pkg/cfg/mux.go deleted file mode 100644 index 6c6f4375..00000000 --- a/pkg/cfg/mux.go +++ /dev/null @@ -1,11 +0,0 @@ -package cfg - -import ( - "net/http" -) - -func WithMux(mux http.Handler) Option { - return func(config *Config) { - config.Mux = mux - } -} diff --git a/pkg/cfg/option.go b/pkg/cfg/option.go deleted file mode 100644 index 0f3e87d8..00000000 --- a/pkg/cfg/option.go +++ /dev/null @@ -1,3 +0,0 @@ -package cfg - -type Option func(*Config) diff --git a/pkg/cfg/tls.go b/pkg/cfg/tls.go deleted file mode 100644 index bce6e186..00000000 --- a/pkg/cfg/tls.go +++ /dev/null @@ -1,75 +0,0 @@ -package cfg - -import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "io/ioutil" - "net/http" - "os" - "path/filepath" - - "github.com/caddyserver/certmagic" - "github.com/xlgmokha/x/pkg/x" - "go.uber.org/zap" -) - -func WithSelfSigned(cert, key string) Option { - certificate := x.Must(tls.LoadX509KeyPair(cert, key)) - - return func(config *Config) { - config.TLS = &tls.Config{ - MinVersion: tls.VersionTLS13, - Certificates: []tls.Certificate{certificate}, - } - } -} - -func WithTLS(domainNames []string) Option { - directoryURL := "https://localhost:8081/acme/acme/directory" - storage := &certmagic.FileStorage{ - Path: filepath.Join(x.Must(os.Getwd()), "/tmp/cache"), - } - var cache *certmagic.Cache - cache = certmagic.NewCache(certmagic.CacheOptions{ - GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) { - return certmagic.New(cache, certmagic.Config{ - Logger: x.Must(zap.NewProduction()), - OnDemand: new(certmagic.OnDemandConfig), - Storage: storage, - }), nil - }, - }) - roots := x.Must(x509.SystemCertPool()) - roots.AddCert(func() *x509.Certificate { - block, _ := pem.Decode(x.Must(ioutil.ReadFile( - filepath.Join(x.Must(os.Getwd()), "/tmp/step/certs/root_ca.crt"), - ))) - return x.Must(x509.ParseCertificate(block.Bytes)) - }()) - magic := certmagic.New(cache, certmagic.Config{ - Logger: x.Must(zap.NewProduction()), - OnDemand: new(certmagic.OnDemandConfig), - Storage: storage, - }) - issuer := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{ - Agreed: true, - Email: "email@example.com", - CA: directoryURL, - TestCA: directoryURL, - TrustedRoots: roots, - }) - magic.Issuers = []certmagic.Issuer{issuer} - - if err := http.ListenAndServe(":80", issuer.HTTPChallengeHandler(http.DefaultServeMux)); err != nil { - return func(*Config) {} - } - - x.Check(magic.ManageSync(context.Background(), domainNames)) - - return func(config *Config) { - config.TLS = magic.TLSConfig() - config.TLS.NextProtos = append([]string{"h2", "http/1.1"}, config.TLS.NextProtos...) - } -} diff --git a/pkg/policies/policies_test.go b/pkg/policies/policies_test.go index 24ef6c68..9dc98bcd 100644 --- a/pkg/policies/policies_test.go +++ b/pkg/policies/policies_test.go @@ -6,7 +6,7 @@ import ( "github.com/cedar-policy/cedar-go" "github.com/stretchr/testify/assert" - "gitlab.com/mokhax/spike/pkg/gid" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authz.d/pkg/gid" ) func build(f func(*cedar.Request)) *cedar.Request { diff --git a/pkg/prxy/prxy.go b/pkg/prxy/prxy.go deleted file mode 100644 index 43565bd3..00000000 --- a/pkg/prxy/prxy.go +++ /dev/null @@ -1,43 +0,0 @@ -package prxy - -import ( - "fmt" - "net" - "net/http" - "net/http/httputil" - "net/url" - - "github.com/xlgmokha/x/pkg/log" - "github.com/xlgmokha/x/pkg/x" -) - -func New(routes map[string]string) http.Handler { - mapped := map[string]*url.URL{} - for source, destination := range routes { - mapped[source] = x.Must(url.Parse(destination)) - } - - return &httputil.ReverseProxy{ - Rewrite: func(r *httputil.ProxyRequest) { - host, _, err := net.SplitHostPort(r.In.Host) - if err != nil { - log.WithFields(r.In.Context(), log.Fields{"error": err}) - return - } - - destination := mapped[host] - r.SetXForwarded() - r.SetURL(destination) - }, - Transport: http.DefaultTransport, - FlushInterval: -1, - ErrorLog: nil, - ModifyResponse: func(r *http.Response) error { - r.Header.Add("Via", fmt.Sprintf("%v gtwy", r.Proto)) - return nil - }, - ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { - log.WithFields(r.Context(), log.Fields{"error": err}) - }, - } -} diff --git a/pkg/prxy/prxy_test.go b/pkg/prxy/prxy_test.go deleted file mode 100644 index 6f37974e..00000000 --- a/pkg/prxy/prxy_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package prxy - -import ( - "net/http" - "net/http/httptest" - "net/url" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/xlgmokha/x/pkg/x" - "gitlab.com/mokhax/spike/pkg/test" -) - -func TestProxy(t *testing.T) { - t.Run("http://idp.test", func(t *testing.T) { - var lastIdPRequest *http.Request - var lastUiRequest *http.Request - - idp := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - lastIdPRequest = r - w.WriteHeader(http.StatusOK) - })) - defer idp.Close() - - ui := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - lastUiRequest = r - w.WriteHeader(http.StatusTeapot) - })) - defer ui.Close() - - subject := New(map[string]string{ - "idp.test": idp.URL, - "ui.test": ui.URL, - }) - - r, w := test.RequestResponse("GET", "http://idp.test:8080/saml/new") - - subject.ServeHTTP(w, r) - - url := x.Must(url.Parse(idp.URL)) - - assert.Nil(t, lastUiRequest) - assert.Equal(t, http.StatusOK, w.Code) - - require.NotNil(t, lastIdPRequest) - assert.Equal(t, url.Host, lastIdPRequest.Host) - }) -} diff --git a/pkg/rpc/ability.pb.go b/pkg/rpc/ability.pb.go index 48dd0b24..939719fc 100644 --- a/pkg/rpc/ability.pb.go +++ b/pkg/rpc/ability.pb.go @@ -129,7 +129,7 @@ var File_ability_proto protoreflect.FileDescriptor const file_ability_proto_rawDesc = "" + "\n" + - "\rability.proto\x12\tauthx.rpc\"d\n" + + "\rability.proto\x12\tauthz.rpc\"d\n" + "\fAllowRequest\x12\x18\n" + "\asubject\x18\x01 \x01(\tR\asubject\x12\x1e\n" + "\n" + @@ -140,7 +140,7 @@ const file_ability_proto_rawDesc = "" + "AllowReply\x12\x16\n" + "\x06result\x18\x01 \x01(\bR\x06result2F\n" + "\aAbility\x12;\n" + - "\aAllowed\x12\x17.authx.rpc.AllowRequest\x1a\x15.authx.rpc.AllowReply\"\x00B!Z\x1fgitlab.com/mokhax/spike/pkg/rpcb\x06proto3" + "\aAllowed\x12\x17.authz.rpc.AllowRequest\x1a\x15.authz.rpc.AllowReply\"\x00B\tZ\apkg/rpcb\x06proto3" var ( file_ability_proto_rawDescOnce sync.Once @@ -156,12 +156,12 @@ func file_ability_proto_rawDescGZIP() []byte { var file_ability_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_ability_proto_goTypes = []any{ - (*AllowRequest)(nil), // 0: authx.rpc.AllowRequest - (*AllowReply)(nil), // 1: authx.rpc.AllowReply + (*AllowRequest)(nil), // 0: authz.rpc.AllowRequest + (*AllowReply)(nil), // 1: authz.rpc.AllowReply } var file_ability_proto_depIdxs = []int32{ - 0, // 0: authx.rpc.Ability.Allowed:input_type -> authx.rpc.AllowRequest - 1, // 1: authx.rpc.Ability.Allowed:output_type -> authx.rpc.AllowReply + 0, // 0: authz.rpc.Ability.Allowed:input_type -> authz.rpc.AllowRequest + 1, // 1: authz.rpc.Ability.Allowed:output_type -> authz.rpc.AllowReply 1, // [1:2] is the sub-list for method output_type 0, // [0:1] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name diff --git a/pkg/rpc/gitlab.com/mokhax/spike/pkg/rpc/ability.twirp.go b/pkg/rpc/ability.twirp.go index ea2c3d17..f5a33296 100644 --- a/pkg/rpc/gitlab.com/mokhax/spike/pkg/rpc/ability.twirp.go +++ b/pkg/rpc/ability.twirp.go @@ -68,7 +68,7 @@ func NewAbilityProtobufClient(baseURL string, client HTTPClient, opts ...twirp.C // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> serviceURL := sanitizeBaseURL(baseURL) - serviceURL += baseServicePath(pathPrefix, "authx.rpc", "Ability") + serviceURL += baseServicePath(pathPrefix, "authz.rpc", "Ability") urls := [1]string{ serviceURL + "Allowed", } @@ -82,7 +82,7 @@ func NewAbilityProtobufClient(baseURL string, client HTTPClient, opts ...twirp.C } func (c *abilityProtobufClient) Allowed(ctx context.Context, in *AllowRequest) (*AllowReply, error) { - ctx = ctxsetters.WithPackageName(ctx, "authx.rpc") + ctx = ctxsetters.WithPackageName(ctx, "authz.rpc") ctx = ctxsetters.WithServiceName(ctx, "Ability") ctx = ctxsetters.WithMethodName(ctx, "Allowed") caller := c.callAllowed @@ -160,7 +160,7 @@ func NewAbilityJSONClient(baseURL string, client HTTPClient, opts ...twirp.Clien // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> serviceURL := sanitizeBaseURL(baseURL) - serviceURL += baseServicePath(pathPrefix, "authx.rpc", "Ability") + serviceURL += baseServicePath(pathPrefix, "authz.rpc", "Ability") urls := [1]string{ serviceURL + "Allowed", } @@ -174,7 +174,7 @@ func NewAbilityJSONClient(baseURL string, client HTTPClient, opts ...twirp.Clien } func (c *abilityJSONClient) Allowed(ctx context.Context, in *AllowRequest) (*AllowReply, error) { - ctx = ctxsetters.WithPackageName(ctx, "authx.rpc") + ctx = ctxsetters.WithPackageName(ctx, "authz.rpc") ctx = ctxsetters.WithServiceName(ctx, "Ability") ctx = ctxsetters.WithMethodName(ctx, "Allowed") caller := c.callAllowed @@ -281,11 +281,11 @@ func (s *abilityServer) handleRequestBodyError(ctx context.Context, resp http.Re // Should be used with caution, it only matches routes generated by Twirp Go clients, // with the default "/twirp" prefix and default CamelCase service and method names. // More info: https://twitchtv.github.io/twirp/docs/routing.html -const AbilityPathPrefix = "/twirp/authx.rpc.Ability/" +const AbilityPathPrefix = "/twirp/authz.rpc.Ability/" func (s *abilityServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { ctx := req.Context() - ctx = ctxsetters.WithPackageName(ctx, "authx.rpc") + ctx = ctxsetters.WithPackageName(ctx, "authz.rpc") ctx = ctxsetters.WithServiceName(ctx, "Ability") ctx = ctxsetters.WithResponseWriter(ctx, resp) @@ -304,7 +304,7 @@ func (s *abilityServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { // Verify path format: [<prefix>]/<package>.<Service>/<Method> prefix, pkgService, method := parseTwirpPath(req.URL.Path) - if pkgService != "authx.rpc.Ability" { + if pkgService != "authz.rpc.Ability" { msg := fmt.Sprintf("no handler for path %q", req.URL.Path) s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) return @@ -518,7 +518,7 @@ func (s *abilityServer) ProtocGenTwirpVersion() string { // that is everything in a Twirp route except for the <Method>. This can be used for routing, // for example to identify the requests that are targeted to this service in a mux. func (s *abilityServer) PathPrefix() string { - return baseServicePath(s.pathPrefix, "authx.rpc", "Ability") + return baseServicePath(s.pathPrefix, "authz.rpc", "Ability") } // ===== @@ -1087,19 +1087,18 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 216 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbd, 0x4e, 0xc3, 0x30, - 0x14, 0x46, 0x29, 0x48, 0x4d, 0x7b, 0x05, 0x8b, 0x25, 0xc0, 0xea, 0xc0, 0x4f, 0xc4, 0xc0, 0x64, - 0x4b, 0x30, 0x32, 0x95, 0x81, 0x07, 0xc8, 0xc8, 0x66, 0xbb, 0x57, 0xad, 0x89, 0x83, 0x2f, 0xfe, - 0x11, 0xcd, 0xdb, 0x23, 0x39, 0x21, 0x8a, 0xd4, 0xf1, 0xf8, 0xc8, 0xfa, 0x8e, 0x2e, 0x5c, 0x29, - 0x6d, 0x9d, 0x4d, 0xbd, 0xa0, 0xe0, 0x93, 0x67, 0x6b, 0x95, 0xd3, 0xe1, 0x28, 0x02, 0x99, 0x7a, - 0x07, 0x97, 0x5b, 0xe7, 0xfc, 0x6f, 0x83, 0x3f, 0x19, 0x63, 0x62, 0x1c, 0xaa, 0x98, 0xf5, 0x17, - 0x9a, 0xc4, 0x17, 0x0f, 0x8b, 0xe7, 0x75, 0xf3, 0x8f, 0xec, 0x0e, 0x80, 0x30, 0x74, 0x36, 0x46, - 0xeb, 0xbf, 0xf9, 0x79, 0x91, 0xb3, 0x17, 0xb6, 0x81, 0x55, 0xc0, 0xe8, 0x73, 0x30, 0xc8, 0x2f, - 0x8a, 0x9d, 0xb8, 0x7e, 0x02, 0x18, 0x57, 0xc8, 0xf5, 0xec, 0x06, 0x96, 0x01, 0x63, 0x76, 0xc3, - 0xc4, 0xaa, 0x19, 0xe9, 0xe5, 0x03, 0xaa, 0xed, 0xd0, 0xc9, 0xde, 0xa0, 0x2a, 0x1f, 0x70, 0xc7, - 0x6e, 0xc5, 0x54, 0x2b, 0xe6, 0xa9, 0x9b, 0xeb, 0x53, 0x41, 0xae, 0xaf, 0xcf, 0xde, 0x1f, 0x3f, - 0xef, 0xf7, 0x36, 0x39, 0xa5, 0x85, 0xf1, 0x9d, 0xec, 0x7c, 0x7b, 0x50, 0x47, 0x19, 0xc9, 0xb6, - 0x28, 0xa9, 0xdd, 0xcb, 0x40, 0x46, 0x2f, 0xcb, 0x21, 0x5e, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, - 0xe2, 0x96, 0x42, 0xb1, 0x19, 0x01, 0x00, 0x00, + // 196 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x4c, 0xca, 0xcc, + 0xc9, 0x2c, 0xa9, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4c, 0x2c, 0x2d, 0xc9, 0xa8, + 0xd2, 0x2b, 0x2a, 0x48, 0x56, 0x4a, 0xe1, 0xe2, 0x71, 0xcc, 0xc9, 0xc9, 0x2f, 0x0f, 0x4a, 0x2d, + 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x92, 0xe0, 0x62, 0x2f, 0x2e, 0x4d, 0xca, 0x4a, 0x4d, 0x2e, 0x91, + 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x82, 0x71, 0x85, 0xe4, 0xb8, 0xb8, 0x0a, 0x52, 0x8b, 0x72, + 0x33, 0x8b, 0x8b, 0x33, 0xf3, 0xf3, 0x24, 0x98, 0xc0, 0x92, 0x48, 0x22, 0x42, 0x52, 0x5c, 0x1c, + 0x45, 0xa9, 0xc5, 0xf9, 0xa5, 0x45, 0xc9, 0xa9, 0x12, 0xcc, 0x60, 0x59, 0x38, 0x5f, 0x49, 0x85, + 0x8b, 0x0b, 0x6a, 0x4b, 0x41, 0x4e, 0xa5, 0x90, 0x18, 0x17, 0x5b, 0x51, 0x6a, 0x71, 0x69, 0x0e, + 0xc4, 0x0a, 0x8e, 0x20, 0x28, 0xcf, 0xc8, 0x8d, 0x8b, 0xdd, 0x11, 0xe2, 0x4e, 0x21, 0x6b, 0x2e, + 0x76, 0xb0, 0x86, 0xd4, 0x14, 0x21, 0x71, 0x3d, 0xb8, 0x6b, 0xf5, 0x90, 0x9d, 0x2a, 0x25, 0x8a, + 0x29, 0x51, 0x90, 0x53, 0xa9, 0xc4, 0xe0, 0xc4, 0x19, 0xc5, 0x5e, 0x90, 0x9d, 0xae, 0x5f, 0x54, + 0x90, 0x9c, 0xc4, 0x06, 0xf6, 0xb0, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x72, 0x35, 0x46, 0x7c, + 0x01, 0x01, 0x00, 0x00, } diff --git a/pkg/rpc/ability_grpc.pb.go b/pkg/rpc/ability_grpc.pb.go deleted file mode 100644 index 4d74cc41..00000000 --- a/pkg/rpc/ability_grpc.pb.go +++ /dev/null @@ -1,121 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v3.19.6 -// source: ability.proto - -package rpc - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.64.0 or later. -const _ = grpc.SupportPackageIsVersion9 - -const ( - Ability_Allowed_FullMethodName = "/authx.rpc.Ability/Allowed" -) - -// AbilityClient is the client API for Ability service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type AbilityClient interface { - Allowed(ctx context.Context, in *AllowRequest, opts ...grpc.CallOption) (*AllowReply, error) -} - -type abilityClient struct { - cc grpc.ClientConnInterface -} - -func NewAbilityClient(cc grpc.ClientConnInterface) AbilityClient { - return &abilityClient{cc} -} - -func (c *abilityClient) Allowed(ctx context.Context, in *AllowRequest, opts ...grpc.CallOption) (*AllowReply, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(AllowReply) - err := c.cc.Invoke(ctx, Ability_Allowed_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// AbilityServer is the server API for Ability service. -// All implementations must embed UnimplementedAbilityServer -// for forward compatibility. -type AbilityServer interface { - Allowed(context.Context, *AllowRequest) (*AllowReply, error) - mustEmbedUnimplementedAbilityServer() -} - -// UnimplementedAbilityServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedAbilityServer struct{} - -func (UnimplementedAbilityServer) Allowed(context.Context, *AllowRequest) (*AllowReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method Allowed not implemented") -} -func (UnimplementedAbilityServer) mustEmbedUnimplementedAbilityServer() {} -func (UnimplementedAbilityServer) testEmbeddedByValue() {} - -// UnsafeAbilityServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to AbilityServer will -// result in compilation errors. -type UnsafeAbilityServer interface { - mustEmbedUnimplementedAbilityServer() -} - -func RegisterAbilityServer(s grpc.ServiceRegistrar, srv AbilityServer) { - // If the following call pancis, it indicates UnimplementedAbilityServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&Ability_ServiceDesc, srv) -} - -func _Ability_Allowed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AllowRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AbilityServer).Allowed(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Ability_Allowed_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AbilityServer).Allowed(ctx, req.(*AllowRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// Ability_ServiceDesc is the grpc.ServiceDesc for Ability service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Ability_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "authx.rpc.Ability", - HandlerType: (*AbilityServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Allowed", - Handler: _Ability_Allowed_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "ability.proto", -} diff --git a/pkg/rpc/ability_service.go b/pkg/rpc/ability_service.go index 18327d52..db2e8fab 100644 --- a/pkg/rpc/ability_service.go +++ b/pkg/rpc/ability_service.go @@ -4,12 +4,11 @@ import ( context "context" "github.com/cedar-policy/cedar-go" - "gitlab.com/mokhax/spike/pkg/gid" - "gitlab.com/mokhax/spike/pkg/policies" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authz.d/pkg/gid" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authz.d/pkg/policies" ) type AbilityService struct { - UnimplementedAbilityServer } func NewAbilityService() *AbilityService { diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go index 08246b5b..a37df9fc 100644 --- a/pkg/rpc/server.go +++ b/pkg/rpc/server.go @@ -1,11 +1,21 @@ package rpc import ( - grpc "google.golang.org/grpc" + fmt "fmt" + http "net/http" ) -func New(options ...grpc.ServerOption) *grpc.Server { - server := grpc.NewServer(options...) - RegisterAbilityServer(server, NewAbilityService()) - return server +func New() http.Handler { + mux := http.NewServeMux() + for _, handler := range handlers() { + fmt.Printf("Registering : %v\n", handler.PathPrefix()) + mux.Handle(handler.PathPrefix(), handler) + } + return mux +} + +func handlers() []TwirpServer { + return []TwirpServer{ + NewAbilityServer(NewAbilityService()), + } } diff --git a/pkg/rpc/server_test.go b/pkg/rpc/server_test.go index da60f86a..fd6e6237 100644 --- a/pkg/rpc/server_test.go +++ b/pkg/rpc/server_test.go @@ -1,35 +1,19 @@ package rpc import ( - "net" + http "net/http" + "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - grpc "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" ) func TestServer(t *testing.T) { - listener, err := net.Listen("tcp", "localhost:0") - require.NoError(t, err) - defer listener.Close() + srv := httptest.NewServer(New()) + defer srv.Close() - server := New() - defer server.Stop() - - go func() { - require.NoError(t, server.Serve(listener)) - }() - - connection, err := grpc.NewClient( - listener.Addr().String(), - grpc.WithTransportCredentials(insecure.NewCredentials()), - ) - require.NoError(t, err) - - defer connection.Close() - client := NewAbilityClient(connection) + client := NewAbilityProtobufClient(srv.URL, &http.Client{}) t.Run("forbids", func(t *testing.T) { reply, err := client.Allowed(t.Context(), &AllowRequest{ diff --git a/pkg/srv/srv.go b/pkg/srv/srv.go deleted file mode 100644 index e7189406..00000000 --- a/pkg/srv/srv.go +++ /dev/null @@ -1,26 +0,0 @@ -package srv - -import ( - "log" - "net/http" - "time" - - "gitlab.com/mokhax/spike/pkg/cfg" -) - -func New(c *cfg.Config) *http.Server { - return &http.Server{ - Addr: c.BindAddress, - Handler: c.Mux, - TLSConfig: c.TLS, - ReadHeaderTimeout: 10 * time.Second, - ReadTimeout: 30 * time.Second, - WriteTimeout: 30 * time.Second, - IdleTimeout: 30 * time.Second, - ErrorLog: log.Default(), - } -} - -func Run(c *cfg.Config) error { - return c.Run(New(c)) -} diff --git a/pkg/test/test.go b/pkg/test/test.go deleted file mode 100644 index 9963323a..00000000 --- a/pkg/test/test.go +++ /dev/null @@ -1,49 +0,0 @@ -package test - -import ( - "context" - "io" - "net/http" - "net/http/httptest" -) - -type RequestOption func(*http.Request) *http.Request - -func Request(method, target string, options ...RequestOption) *http.Request { - request := httptest.NewRequest(method, target, nil) - for _, option := range options { - request = option(request) - } - return request -} - -func RequestResponse(method, target string, options ...RequestOption) (*http.Request, *httptest.ResponseRecorder) { - return Request(method, target, options...), httptest.NewRecorder() -} - -func WithRequestHeader(key, value string) RequestOption { - return func(r *http.Request) *http.Request { - r.Header.Set(key, value) - return r - } -} - -func WithRequestBody(body io.ReadCloser) RequestOption { - return func(r *http.Request) *http.Request { - r.Body = body - return r - } -} - -func WithContext(ctx context.Context) RequestOption { - return func(r *http.Request) *http.Request { - return r.WithContext(ctx) - } -} - -func WithCookie(cookie *http.Cookie) RequestOption { - return func(r *http.Request) *http.Request { - r.AddCookie(cookie) - return r - } -} diff --git a/protos/ability.proto b/protos/ability.proto index b440abcc..b58f5027 100644 --- a/protos/ability.proto +++ b/protos/ability.proto @@ -1,7 +1,7 @@ syntax = "proto3"; -package authx.rpc; -option go_package = "gitlab.com/mokhax/spike/pkg/rpc"; +package authz.rpc; +option go_package = "pkg/rpc"; service Ability { diff --git a/script/cibuild b/script/cibuild deleted file mode 100755 index b3da3e15..00000000 --- a/script/cibuild +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env ruby - -fork do - exec "mage servers" -end - -# Let the servers boot up -sleep 1 - -test_pid = fork do - exec "mage test" -end - -Process.wait(test_pid) -Process.kill('TERM', 0) diff --git a/test/e2e_test.go b/test/e2e_test.go deleted file mode 100644 index a36049e3..00000000 --- a/test/e2e_test.go +++ /dev/null @@ -1,329 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/base64" - "net/http" - "net/url" - "strings" - "testing" - "time" - - "github.com/playwright-community/playwright-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/xlgmokha/x/pkg/env" - "github.com/xlgmokha/x/pkg/serde" - "github.com/xlgmokha/x/pkg/x" - "golang.org/x/oauth2" -) - -func TestAuthx(t *testing.T) { - if env.Fetch("SKIP_E2E", "") != "" { - t.Skip() - } - - _ = playwright.Install() - - pw := x.Must(playwright.Run()) - browser := x.Must(pw.Firefox.Launch(playwright.BrowserTypeLaunchOptions{ - Headless: playwright.Bool(env.Fetch("HEADLESS", "true") == "true"), - SlowMo: playwright.Float(1000), - })) - page := x.Must(browser.NewPage()) - - client := &http.Client{Timeout: 2 * time.Second} - - defer func() { - x.Check(browser.Close()) - x.Check(pw.Stop()) - }() - - t.Run("SAML", func(t *testing.T) { - for _, url := range []string{"http://idp.example.com:8080/saml/metadata.xml", "http://ui.example.com:8080/saml/metadata.xml"} { - t.Run("GET "+url, func(t *testing.T) { - response := x.Must(http.Get(url)) - assert.Equal(t, http.StatusOK, response.StatusCode) - }) - } - - t.Run("GET http://ui.example.com:8080/saml/new", func(t *testing.T) { - assert.NoError(t, page.Context().ClearCookies()) - x.Must(page.Goto("http://ui.example.com:8080/saml/new")) - action := x.Must(page.Locator("#idp-form").GetAttribute("action")) - assert.Equal(t, "http://idp.example.com:8080/saml/new", action) - assert.NoError(t, page.Locator("#submit-button").Click()) - - page.Locator("#username").Fill("root") - page.Locator("#password").Fill("root") - assert.NoError(t, page.Locator("#login-button").Click()) - - action = x.Must(page.Locator("#postback-form").GetAttribute("action")) - assert.Equal(t, "http://ui.example.com:8080/saml/assertions", action) - assert.NoError(t, page.Locator("#submit-button").Click()) - assert.Contains(t, x.Must(page.Content()), "Received SAML Response") - - t.Run("generates a usable access token", func(t *testing.T) { - rawToken := x.Must(page.Locator("#access-token").TextContent()) - accessToken := strings.Replace(rawToken, "\"", "", -1) - assert.NotEmpty(t, accessToken) - - t.Run("GET http://api.example.com:8080/projects.json", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/projects.json", nil)) - request.Header.Add("Authorization", "Bearer "+accessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - projects := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, projects) - }) - }) - - t.Run("exchange SAML assertion for access token", func(t *testing.T) { - samlAssertion := x.Must(page.Locator("#raw-saml-response").TextContent()) - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{ - "assertion": samlAssertion, - "grant_type": "urn:ietf:params:oauth:grant-type:saml2-bearer", - })) - request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://idp.example.com:8080/oauth/token", io)) - request.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("client_id:client_secret"))) - request.Header.Add("Content-Type", "application/json ") - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - }) - }) - }) - - t.Run("OIDC", func(t *testing.T) { - t.Run("GET http://ui.example.com:8080/oidc/new", func(t *testing.T) { - assert.NoError(t, page.Context().ClearCookies()) - x.Must(page.Goto("http://ui.example.com:8080/oidc/new")) - - assert.Contains(t, page.URL(), "http://idp.example.com:8080/sessions/new") - page.Locator("#username").Fill("root") - page.Locator("#password").Fill("root") - assert.NoError(t, page.Locator("#login-button").Click()) - - assert.Contains(t, page.URL(), "http://idp.example.com:8080/oauth/authorize/continue") - assert.NoError(t, page.Locator("#submit-button").Click()) - - assert.Contains(t, page.URL(), "http://ui.example.com:8080/oauth/callback") - content := x.Must(page.Locator("pre").First().InnerText()) - item := x.Must(serde.FromJSON[oauth2.Token](strings.NewReader(content))) - require.NotEmpty(t, item.AccessToken) - require.Equal(t, "Bearer", item.TokenType) - require.NotEmpty(t, item.RefreshToken) - - t.Run("GET http://api.example.com:8080/organizations.json", func(t *testing.T) { - response := x.Must(http.Get("http://api.example.com:8080/organizations.json")) - assert.Equal(t, http.StatusForbidden, response.StatusCode) - }) - - t.Run("GET http://api.example.com:8080/organizations.json with Authorization", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/organizations.json", nil)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - organizations := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, organizations) - }) - - t.Run("GET http://api.example.com:8080/groups.json", func(t *testing.T) { - response := x.Must(http.Get("http://api.example.com:8080/groups.json")) - assert.Equal(t, http.StatusForbidden, response.StatusCode) - }) - - t.Run("GET http://api.example.com:8080/groups.json with Authorization", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/groups.json", nil)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - groups := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, groups) - }) - - t.Run("GET http://api.example.com:8080/projects.json", func(t *testing.T) { - response := x.Must(http.Get("http://api.example.com:8080/projects.json")) - assert.Equal(t, http.StatusForbidden, response.StatusCode) - }) - - t.Run("GET http://api.example.com:8080/projects.json with Authorization", func(t *testing.T) { - request := x.Must(http.NewRequestWithContext(t.Context(), "GET", "http://api.example.com:8080/projects.json", nil)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusOK, response.StatusCode) - projects := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, projects) - }) - - t.Run("creates a new project", func(t *testing.T) { - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "example"})) - request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://api.example.com:8080/projects", io)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusCreated, response.StatusCode) - project := x.Must(serde.FromJSON[map[string]string](response.Body)) - assert.Equal(t, "example", project["name"]) - }) - - t.Run("creates another project", func(t *testing.T) { - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "example2"})) - request := x.Must(http.NewRequestWithContext(t.Context(), "POST", "http://api.example.com:8080/projects.json", io)) - request.Header.Add("Authorization", "Bearer "+item.AccessToken) - response := x.Must(client.Do(request)) - require.Equal(t, http.StatusCreated, response.StatusCode) - project := x.Must(serde.FromJSON[map[string]string](response.Body)) - assert.Equal(t, "example2", project["name"]) - }) - }) - }) - - t.Run("OAuth", func(t *testing.T) { - t.Run("GET /.well-known/oauth-authorization-server", func(t *testing.T) { - response := x.Must(client.Get("http://idp.example.com:8080/.well-known/oauth-authorization-server")) - require.Equal(t, http.StatusOK, response.StatusCode) - metadata := x.Must(serde.FromJSON[map[string]interface{}](response.Body)) - assert.Equal(t, "http://idp.example.com:8080/.well-known/oauth-authorization-server", metadata["issuer"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/authorize", metadata["authorization_endpoint"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/token", metadata["token_endpoint"]) - // assert.NotEmpty(t, metadata["jwks_uri"]) - // assert.NotEmpty(t, metadata["registration_endpoint"]) - assert.NotEmpty(t, metadata["scopes_supported"]) - assert.NotEmpty(t, metadata["response_types_supported"]) - assert.NotEmpty(t, metadata["response_modes_supported"]) - assert.NotEmpty(t, metadata["grant_types_supported"]) - assert.NotEmpty(t, metadata["token_endpoint_auth_methods_supported"]) - assert.NotEmpty(t, metadata["token_endpoint_auth_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["service_documentation"]) - assert.NotEmpty(t, metadata["ui_locales_supported"]) - // assert.NotEmpty(t, metadata["op_policy_uri"]) - // assert.NotEmpty(t, metadata["op_tos_uri"]) - assert.NotEmpty(t, metadata["revocation_endpoint"]) - assert.NotEmpty(t, metadata["revocation_endpoint_auth_methods_supported"]) - assert.NotEmpty(t, metadata["revocation_endpoint_auth_signing_alg_values_supported"]) - assert.NotEmpty(t, metadata["introspection_endpoint"]) - assert.NotEmpty(t, metadata["introspection_endpoint_auth_methods_supported"]) - assert.NotEmpty(t, metadata["introspection_endpoint_auth_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["code_challenge_methods_supported"]) - }) - - t.Run("GET /.well-known/openid-configuration", func(t *testing.T) { - response := x.Must(client.Get("http://idp.example.com:8080/.well-known/openid-configuration")) - require.Equal(t, http.StatusOK, response.StatusCode) - metadata := x.Must(serde.FromJSON[map[string]interface{}](response.Body)) - assert.Equal(t, "http://idp.example.com:8080/.well-known/oauth-authorization-server", metadata["issuer"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/authorize", metadata["authorization_endpoint"]) - assert.Equal(t, "http://idp.example.com:8080/oauth/token", metadata["token_endpoint"]) - assert.NotEmpty(t, metadata["userinfo_endpoint"]) - // assert.NotEmpty(t, metadata["jwks_uri"]) - // assert.NotEmpty(t, metadata["registration_endpoint"]) - assert.NotEmpty(t, metadata["scopes_supported"]) - assert.NotEmpty(t, metadata["response_types_supported"]) - assert.NotEmpty(t, metadata["response_modes_supported"]) - assert.NotEmpty(t, metadata["grant_types_supported"]) - // assert.NotEmpty(t, metadata["acr_values_supported"]) - assert.NotEmpty(t, metadata["subject_types_supported"]) - assert.NotEmpty(t, metadata["id_token_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["id_token_encryption_alg_values_supported"]) - // assert.NotEmpty(t, metadata["id_token_encryption_enc_values_supported"]) - assert.NotEmpty(t, metadata["userinfo_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["userinfo_encryption_alg_values_supported"]) - // assert.NotEmpty(t, metadata["userinfo_encryption_enc_values_supported"]) - assert.NotEmpty(t, metadata["request_object_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["request_object_encryption_alg_values_supported"]) - // assert.NotEmpty(t, metadata["request_object_encryption_enc_values_supported"]) - assert.NotEmpty(t, metadata["token_endpoint_auth_methods_supported"]) - // assert.NotEmpty(t, metadata["token_endpoint_auth_signing_alg_values_supported"]) - // assert.NotEmpty(t, metadata["display_values_supported"]) - assert.NotEmpty(t, metadata["claim_types_supported"]) - assert.NotEmpty(t, metadata["claims_supported"]) - // assert.NotEmpty(t, metadata["service_documentation"]) - // assert.NotEmpty(t, metadata["claims_locales_supported"]) - assert.NotEmpty(t, metadata["ui_locales_supported"]) - // assert.True(t, metadata["claims_parameter_supported"]) - // assert.True(t, metadata["request_parameter_supported"]) - // assert.True(t, metadata["request_uri_parameter_supported"]) - // assert.True(t, metadata["require_request_uri_registration"]) - // assert.NotEmpty(t, metadata["op_policy_uri"]) - // assert.NotEmpty(t, metadata["op_tos_uri"]) - }) - - t.Run("authorization code grant", func(t *testing.T) { - conf := &oauth2.Config{ - ClientID: "client_id", - ClientSecret: "client_secret", - Scopes: []string{"openid"}, - Endpoint: oauth2.Endpoint{ - TokenURL: "http://idp.example.com:8080/oauth/token", - AuthURL: "http://idp.example.com:8080/oauth/authorize", - }, - } - - authURL := conf.AuthCodeURL( - "state", - oauth2.SetAuthURLParam("client_id", "client_id"), - oauth2.SetAuthURLParam("scope", "openid"), - oauth2.SetAuthURLParam("redirect_uri", "http://example.org/oauth/callback"), - oauth2.SetAuthURLParam("response_type", "code"), - oauth2.SetAuthURLParam("response_mode", "fragment"), - ) - assert.NoError(t, page.Context().ClearCookies()) - x.Must(page.Goto(authURL)) - - page.Locator("#username").Fill("root") - page.Locator("#password").Fill("root") - assert.NoError(t, page.Locator("#login-button").Click()) - - assert.NoError(t, page.Locator("#submit-button").Click()) - - uri := x.Must(url.Parse(page.URL())) - values := x.Must(url.ParseQuery(uri.Fragment)) - code := values.Get("code") - - ctx := t.Context() - ctx = context.WithValue(ctx, oauth2.HTTPClient, client) - credentials := x.Must(conf.Exchange(ctx, code)) - assert.NotEmpty(t, credentials.AccessToken) - assert.Equal(t, "Bearer", credentials.TokenType) - assert.NotEmpty(t, credentials.RefreshToken) - - t.Run("cannot re-use the same authorization grant", func(t *testing.T) { - newCredentials, err := conf.Exchange(ctx, code) - - assert.Error(t, err) - assert.Empty(t, newCredentials) - }) - - t.Run("token is usable against REST API", func(t *testing.T) { - client := conf.Client(ctx, credentials) - response := x.Must(client.Get("http://api.example.com:8080/projects.json")) - require.Equal(t, http.StatusOK, response.StatusCode) - projects := x.Must(serde.FromJSON[[]map[string]string](response.Body)) - assert.NotNil(t, projects) - - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"name": "foo"})) - response = x.Must(client.Post("http://api.example.com:8080/projects", "application/json", io)) - require.Equal(t, http.StatusCreated, response.StatusCode) - project := x.Must(serde.FromJSON[map[string]string](response.Body)) - assert.Equal(t, "foo", project["name"]) - }) - - t.Run("token can be introspected", func(t *testing.T) { - client := conf.Client(ctx, credentials) - - io := bytes.NewBuffer(nil) - assert.NoError(t, serde.ToJSON(io, map[string]string{"token": credentials.AccessToken})) - response := x.Must(client.Post("http://idp.example.com:8080/oauth/introspect", "application/json", io)) - require.Equal(t, http.StatusOK, response.StatusCode) - - claims := x.Must(serde.FromJSON[map[string]interface{}](response.Body)) - assert.Equal(t, true, claims["active"]) - assert.Equal(t, "gid://example/User/1", claims["sub"]) - }) - }) - }) -} |
