Require nonblank notification identities
This commit is contained in:
@@ -135,6 +135,9 @@ Distributor notification is disabled by default. Its fields are:
|
|||||||
The upload token is read from the environment variable named by `token_env`.
|
The upload token is read from the environment variable named by `token_env`.
|
||||||
Use `secrets.directory` when a file-backed secret is appropriate.
|
Use `secrets.directory` when a file-backed secret is appropriate.
|
||||||
|
|
||||||
|
When notification is enabled, each rendered single-report pipeline ID, bundle
|
||||||
|
ID, and idempotency key must contain at least one non-whitespace character.
|
||||||
|
|
||||||
Single-report bundle templates accept `location_id`, `report_id`, `run_id`,
|
Single-report bundle templates accept `location_id`, `report_id`, `run_id`,
|
||||||
`artifact_group`, `batch_output_name`, `valid_start_date`, `valid_end_date`,
|
`artifact_group`, `batch_output_name`, `valid_start_date`, `valid_end_date`,
|
||||||
`valid_start_time`, `valid_end_time`, `valid_start_stamp`, `valid_end_stamp`,
|
`valid_start_time`, `valid_end_time`, `valid_start_stamp`, `valid_end_stamp`,
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ A successful response is `202 Accepted` with JSON containing `run_id` and
|
|||||||
`status`. Acceptance means Distributor staged and validated the source bundle;
|
`status`. Acceptance means Distributor staged and validated the source bundle;
|
||||||
it does not mean downstream destinations have published it.
|
it does not mean downstream destinations have published it.
|
||||||
|
|
||||||
The adapter requires a pipeline ID, bundle ID, idempotency key, and at least one
|
The adapter requires nonblank pipeline ID, bundle ID, and idempotency key, plus
|
||||||
source-file mapping before calling Distributor. It reads the bearer token from
|
at least one source-file mapping, before calling Distributor. It reads the bearer token from
|
||||||
the configured environment variable and redacts that value from errors. Request
|
the configured environment variable and redacts that value from errors. Request
|
||||||
construction and timeout handling belong to the [Distributor adapter](../../internal/distributor-adapter.md).
|
construction and timeout handling belong to the [Distributor adapter](../../internal/distributor-adapter.md).
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ returns a failed batch status even when all report counters show success; the
|
|||||||
top-level notification result contains the delivery diagnostic.
|
top-level notification result contains the delivery diagnostic.
|
||||||
|
|
||||||
For a single report, Distributor notification follows the atomic output write.
|
For a single report, Distributor notification follows the atomic output write.
|
||||||
|
Enabled notification templates are validated before report processing, including
|
||||||
|
the requirement that each rendered identity contains a non-whitespace character.
|
||||||
See the [configuration reference](config.md) for pipeline, bundle,
|
See the [configuration reference](config.md) for pipeline, bundle,
|
||||||
idempotency-key, and per-report path templates.
|
idempotency-key, and per-report path templates.
|
||||||
|
|
||||||
|
|||||||
@@ -1285,6 +1285,13 @@ func TestEnabledDistributorNotifyValidation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: "notify.distributor.bundle_id_template",
|
wantErr: "notify.distributor.bundle_id_template",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "BundleTemplateRenderedEmpty",
|
||||||
|
mutate: func(cfg *Config) {
|
||||||
|
cfg.Notify.Distributor.BundleIDTemplate = " "
|
||||||
|
},
|
||||||
|
wantErr: "notify.distributor.bundle_id_template",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "IdempotencyTemplate",
|
name: "IdempotencyTemplate",
|
||||||
mutate: func(cfg *Config) {
|
mutate: func(cfg *Config) {
|
||||||
@@ -1292,6 +1299,13 @@ func TestEnabledDistributorNotifyValidation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: "notify.distributor.idempotency_key_template",
|
wantErr: "notify.distributor.idempotency_key_template",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "IdempotencyTemplateRenderedEmpty",
|
||||||
|
mutate: func(cfg *Config) {
|
||||||
|
cfg.Notify.Distributor.IdempotencyKeyTemplate = " "
|
||||||
|
},
|
||||||
|
wantErr: "notify.distributor.idempotency_key_template",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "BatchTemplate",
|
name: "BatchTemplate",
|
||||||
mutate: func(cfg *Config) {
|
mutate: func(cfg *Config) {
|
||||||
|
|||||||
@@ -78,7 +78,14 @@ var distributorBatchIdempotencyTemplateVariables = map[string]struct{}{
|
|||||||
var distributorBatchPipelineTemplateVariables = distributorBatchTemplateVariables
|
var distributorBatchPipelineTemplateVariables = distributorBatchTemplateVariables
|
||||||
|
|
||||||
func RenderDistributorBundleID(template string, values DistributorTemplateValues) (string, error) {
|
func RenderDistributorBundleID(template string, values DistributorTemplateValues) (string, error) {
|
||||||
return renderDistributorTemplate("notify.distributor.bundle_id_template", template, values, distributorTemplateVariables)
|
rendered, err := renderDistributorTemplate("notify.distributor.bundle_id_template", template, values, distributorTemplateVariables)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(rendered) == "" {
|
||||||
|
return "", fmt.Errorf("notify.distributor.bundle_id_template renders an empty bundle id")
|
||||||
|
}
|
||||||
|
return rendered, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderDistributorPipelineID(template string, values DistributorTemplateValues) (string, error) {
|
func RenderDistributorPipelineID(template string, values DistributorTemplateValues) (string, error) {
|
||||||
@@ -93,7 +100,14 @@ func RenderDistributorPipelineID(template string, values DistributorTemplateValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RenderDistributorIdempotencyKey(template string, values DistributorTemplateValues) (string, error) {
|
func RenderDistributorIdempotencyKey(template string, values DistributorTemplateValues) (string, error) {
|
||||||
return renderDistributorTemplate("notify.distributor.idempotency_key_template", template, values, distributorIdempotencyTemplateVariables)
|
rendered, err := renderDistributorTemplate("notify.distributor.idempotency_key_template", template, values, distributorIdempotencyTemplateVariables)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(rendered) == "" {
|
||||||
|
return "", fmt.Errorf("notify.distributor.idempotency_key_template renders an empty idempotency key")
|
||||||
|
}
|
||||||
|
return rendered, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderDistributorBatchBundleID(template string, values DistributorBatchTemplateValues) (string, error) {
|
func RenderDistributorBatchBundleID(template string, values DistributorBatchTemplateValues) (string, error) {
|
||||||
|
|||||||
@@ -152,6 +152,9 @@ func validateDistributorNotify(cfg DistributorNotifyConfig) error {
|
|||||||
if _, err := RenderDistributorPipelineID(cfg.PipelineIDTemplate, values); err != nil {
|
if _, err := RenderDistributorPipelineID(cfg.PipelineIDTemplate, values); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if _, err := RenderDistributorIdempotencyKey(cfg.IdempotencyKeyTemplate, values); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := validateDistributorBatchNotify(cfg.Batch); err != nil {
|
if err := validateDistributorBatchNotify(cfg.Batch); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user