syntax = "proto3";
package spire.api.server.bundle.v1;
option go_package = "github.com/spiffe/spire-api-sdk/proto/spire/api/server/bundle/v1;bundlev1";

import "spire/api/types/bundle.proto";
import "spire/api/types/status.proto";

service Bundle {
    // Count bundles.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc CountBundles(CountBundlesRequest) returns (CountBundlesResponse);

    // Gets the bundle for the trust domain of the server.
    //
    // The RPC does not require authentication.
    rpc GetBundle(GetBundleRequest) returns (spire.api.types.Bundle);

    // Append to the bundle. Items specified in the bundle in the request are
    // appended to the existing bundle. If the bundle does not exist, NOT_FOUND
    // is returned. This is the only RPC that can be used to update the
    // bundle for the trust domain of the SPIRE server.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc AppendBundle(AppendBundleRequest) returns (spire.api.types.Bundle);

    // Publishes a downstream JWT authority to the SPIRE server. If the server
    // is itself a downstream server (i.e. configured with an UpstreamAuthority
    // plugin), the JWT authority is published further upstream using the
    // UpstreamAuthority plugin. If the server is not a downstream server, or
    // if the UpstreamAuthority does not support publishing JWT authorities,
    // the server appends the JWT authority to its own bundle.
    //
    // The caller must present a downstream X509-SVID.
    rpc PublishJWTAuthority(PublishJWTAuthorityRequest) returns (PublishJWTAuthorityResponse);

    // Publishes a downstream WIT authority to the SPIRE server. If the server
    // is itself a downstream server (i.e. configured with an UpstreamAuthority
    // plugin), the WIT authority is published further upstream using the
    // UpstreamAuthority plugin. If the server is not a downstream server, or
    // if the UpstreamAuthority does not support publishing WIT authorities,
    // the server appends the WIT authority to its own bundle.
    //
    // The caller must present a downstream X509-SVID.
    rpc PublishWITAuthority(PublishWITAuthorityRequest) returns (PublishWITAuthorityResponse);

    // Lists federated bundles.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc ListFederatedBundles(ListFederatedBundlesRequest) returns (ListFederatedBundlesResponse);

    // Gets a federated bundle. If the bundle does not exist, NOT_FOUND is returned.
    //
    // The caller must be local or present an admin or an active agent X509-SVID.
    rpc GetFederatedBundle(GetFederatedBundleRequest) returns (spire.api.types.Bundle);

    // Batch creates one or more federated bundles.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc BatchCreateFederatedBundle(BatchCreateFederatedBundleRequest) returns (BatchCreateFederatedBundleResponse);

    // Batch updates one or more federated bundles.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc BatchUpdateFederatedBundle(BatchUpdateFederatedBundleRequest) returns (BatchUpdateFederatedBundleResponse);

    // Batch upserts one or more federated bundles.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc BatchSetFederatedBundle(BatchSetFederatedBundleRequest) returns (BatchSetFederatedBundleResponse);

    // Batch deletes one or more federated bundles.
    //
    // The caller must be local or present an admin X509-SVID.
    rpc BatchDeleteFederatedBundle(BatchDeleteFederatedBundleRequest) returns (BatchDeleteFederatedBundleResponse);
}

message CountBundlesRequest {
}

message CountBundlesResponse {
    // The total number of bundles, including the server bundle.
    int32 count = 1;
}

message GetBundleRequest {
    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 1;
}

message AppendBundleRequest {
    // X.509 authorities to append.
    repeated spire.api.types.X509Certificate x509_authorities = 1;

    // JWT authorities to append.
    repeated spire.api.types.JWTKey jwt_authorities = 2;

    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 3;

    // WIT authorities to append.
    repeated spire.api.types.WITKey wit_authorities = 4;
}

message PublishJWTAuthorityRequest {
    // Required. The JWT authority to publish.
    spire.api.types.JWTKey jwt_authority = 1;
}

message PublishJWTAuthorityResponse {
    // The JWT authorities for the trust domain.
    repeated spire.api.types.JWTKey jwt_authorities = 1;
}

message PublishWITAuthorityRequest {
    // Required. The WIT authority to publish.
    spire.api.types.WITKey wit_authority = 1;
}

message PublishWITAuthorityResponse {
    // The WIT authorities for the trust domain.
    repeated spire.api.types.WITKey wit_authorities = 1;
}


message ListFederatedBundlesRequest {
    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 1;

    // The maximum number of results to return. The server may further
    // constrain this value, or if zero, choose its own.
    int32 page_size = 2;

    // The next_page_token value returned from a previous request, if any.
    string page_token = 3;
}

message ListFederatedBundlesResponse {
    // The bundles.
    repeated spire.api.types.Bundle bundles = 1;

    // The page token for the next request. Empty if there are no more results.
    // This field should be checked by clients even when a page_size was not
    // requested, since the server may choose its own (see page_size).
    string next_page_token = 2;
}

message GetFederatedBundleRequest {
    // Required. The trust domain name of the bundle (e.g., "example.org").
    string trust_domain = 1;

    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 2;
}

message BatchCreateFederatedBundleRequest {
    // The bundles to be created.
    repeated spire.api.types.Bundle bundle = 1;

    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 2;
}

message BatchCreateFederatedBundleResponse {
    message Result {
        // The status of creating the bundle.
        spire.api.types.Status status = 1;

        // The bundle that was created. This will be set if the status is OK.
        spire.api.types.Bundle bundle = 2;
    }

    // Result for each bundle in the request (order is maintained).
    repeated Result results = 1;
}

message BatchUpdateFederatedBundleRequest {
    // The bundles to be updated.
    repeated spire.api.types.Bundle bundle = 1;

    // An input mask indicating which bundle fields should be updated.
    spire.api.types.BundleMask input_mask = 2;

    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 3;
}

message BatchUpdateFederatedBundleResponse {
    message Result {
        // The status of updating the bundle.
        spire.api.types.Status status = 1;

        // The bundle that was updated. This will be set if the status is OK.
        spire.api.types.Bundle bundle = 2;
    }

    // Result for each bundle in the request (order is maintained).
    repeated Result results = 1;
}

message BatchSetFederatedBundleRequest {
    // The bundles to be upserted.
    repeated spire.api.types.Bundle bundle = 1;

    // An output mask indicating which bundle fields are set in the response.
    spire.api.types.BundleMask output_mask = 2;
}

message BatchSetFederatedBundleResponse {
    message Result {
        // The status of upserting the bundle.
        spire.api.types.Status status = 1;

        // The bundle that was upserted. This will be set if the status is OK.
        spire.api.types.Bundle bundle = 2;
    }

    // Result for each bundle in the request (order is maintained).
    repeated Result results = 1;
}

message BatchDeleteFederatedBundleRequest {
    // Mode controls the delete behavior if there are other records
    // associated with the bundle (e.g. registration entries).
    enum Mode {
        // RESTRICT prevents the bundle from being deleted in the presence of associated entries
        RESTRICT = 0;
        // DELETE deletes the bundle and associated entries
        DELETE = 1;
        // DISSOCIATE deletes the bundle and dissociates associated entries
        DISSOCIATE = 2;
    }

    // The trust domain names (e.g., "example.org") of the bundles to delete.
    repeated string trust_domains = 1;

    // The deletion mode selected
    Mode mode = 2;
}

message BatchDeleteFederatedBundleResponse {
    message Result {
        // The status of deleting the bundle.
        spire.api.types.Status status = 1;

        // The trust domain name (e.g., "example.org") of the bundle that was
        // deleted.
        string trust_domain = 2;
    }

    // Result for each trust domain name in the request (order is maintained).
    repeated Result results = 1;
}
