forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: refactor from githubactionsevent to githubactions
- Loading branch information
Showing
47 changed files
with
9,613 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
include ../../Makefile.Common | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# GitHub Actions Receiver | ||
|
||
<!-- status autogenerated section --> | ||
| Status | | | ||
| ------------- |-----------| | ||
| Stability | [alpha]: traces | | ||
| Distributions | [] | | ||
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fgithubactionsevent%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fgithubactionsevent) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fgithubactionsevent%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fgithubactionsevent) | | ||
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@krzko](https://www.github.com/krzko), [@rich-bain](https://www.github.com/rich-bain) | | ||
|
||
[alpha]: https://github.com/open-telemetry/opentelemetry-collector#alpha | ||
<!-- end autogenerated section --> | ||
|
||
The GitHub Actions Receiver processes GitHub Actions webhook events to observe workflows and jobs. It handles [`workflow_job`](https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_job) and [`workflow_run`](https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_run) event payloads, transforming them into `trace` telemetry. | ||
|
||
Each GitHub Action workflow or job, along with its steps, are converted into trace spans, allowing the observation of workflow execution times, success, and failure rates. | ||
|
||
If a secret is configured (recommended), it [validates the payload](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries) ensuring data integrity before processing. | ||
|
||
## Configuration | ||
|
||
The following settings are required: | ||
|
||
* `endpoint` (no default): The endpoint where you may point your webhook to emit events to | ||
|
||
The following settings are optional: | ||
|
||
* `path` (default: '/events'): Path where the receiver instance will accept events | ||
* `secret`: GitHub webhook hash signature | ||
|
||
Example: | ||
```yaml | ||
receivers: | ||
githubactions: | ||
endpoint: localhost:19418 | ||
path: /events | ||
secret: It's a Secret to Everybody | ||
``` | ||
The full list of settings exposed for this receiver are documented [here](./config.go) with a detailed sample configuration [here](./testdata/config.yaml) | ||
## GitHub repository webhooks | ||
Webhooks provide a way for notifications to be delivered to an external web server whenever certain events occur on GitHub. | ||
### Delivery headers | ||
HTTP POST payloads that are delivered to your webhook's configured URL endpoint will contain several special headers: | ||
* `X-Hub-Signature`: This header is sent if the webhook is configured with a `secret`. This is the HMAC hex digest of the request body, and is generated using the SHA-1 hash function and the `secret` as the HMAC `key`. `X-Hub-Signature` is provided for compatibility with existing integrations. It's recommended that you use the more secure `X-Hub-Signature-256` instead. | ||
* `X-Hub-Signature-256`: This header is sent if the webhook is configured with a `secret` (recommended). This is the HMAC hex digest of the request body, and is generated using the SHA-256 hash function and the `secret` as the HMAC `key`. | ||
* `User-Agent`: This header will always have the prefix `GitHub-Hookshot/`. | ||
|
||
### Creating webhooks | ||
|
||
You can create webhooks to subscribe to specific events that occur on GitHub. | ||
|
||
#### Creating a respositoty webhook | ||
|
||
You can create a webhook to subscribe to events that occur in a specific repository. You must be a repository owner or have admin access in the repository to create webhooks in that repository. | ||
|
||
1. On **github.com**, navigate to the main page of the repository. | ||
2. Under your repository name, click **Settings**. If you cannot see the "Settings" tab, select the dropdown menu, then click Settings. | ||
3. In the left sidebar, click **Webhooks**. | ||
4. Click Add **webhook**. | ||
5. Under "Payload URL", type the URL where you'd like to receive payloads. | ||
6. Select the **Content type** drop-down menu, and click a data format to receive the webhook payload in. | ||
* Select `application/json`, which will deliver the JSON payload directly as the body of the `POST` request. | ||
7. Optionally (recomended), under "Secret", type a string to use as a secret key. You should choose a random string of text with high entropy. You can use the webhook secret to limit incoming requests to only those originating from GitHub. | ||
8. Under "Which events would you like to trigger this webhook?" | ||
* Select **Let me select individual events**. | ||
* Uncheck **Pushes**, which is selected by default. | ||
* Select **Workflow jobs**. | ||
* Select **Workflow runs**. | ||
9. To make the webhook active immediately after adding the configuration, select **Active**. | ||
10. Click **Add webhook**. | ||
|
||
You can use the GitHub web interface or the REST API to create a repository webhook. For more information about using the REST API to create a repository webhook, see [Repository Webhooks](https://docs.github.com/en/rest/webhooks/repos?apiVersion=2022-11-28#create-a-repository-webhook). | ||
|
||
Alternatively you can use a configuration management tool such as [`terraform`](https://www.terraform.io/) with the [`github_repository_webhook`](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_webhook.html) resource, to configure webhooks. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package githubactionsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubactionsreceiver" | ||
|
||
import ( | ||
"errors" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
|
||
"go.uber.org/multierr" | ||
) | ||
|
||
var errMissingEndpointFromConfig = errors.New("missing receiver server endpoint from config") | ||
|
||
// Config defines configuration for GitHub Actions receiver | ||
type Config struct { | ||
confighttp.HTTPServerSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct | ||
Path string `mapstructure:"path"` // path for data collection. Default is <host>:<port>/events | ||
Secret string `mapstructure:"secret"` // github webhook hash signature. Default is empty | ||
CustomServiceName string `mapstructure:"custom_service_name"` // custom service name. Default is empty | ||
ServiceNamePrefix string `mapstructure:"service_name_prefix"` // service name prefix. Default is empty | ||
ServiceNameSuffix string `mapstructure:"service_name_suffix"` // service name suffix. Default is empty | ||
} | ||
|
||
var _ component.Config = (*Config)(nil) | ||
|
||
// Validate checks the receiver configuration is valid | ||
func (cfg *Config) Validate() error { | ||
var errs error | ||
|
||
if cfg.HTTPServerSettings.Endpoint == "" { | ||
errs = multierr.Append(errs, errMissingEndpointFromConfig) | ||
} | ||
|
||
return errs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package githubactionsreceiver | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
"go.opentelemetry.io/collector/confmap/confmaptest" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubactionsreceiver/internal/metadata" | ||
) | ||
|
||
// only one validate check so far | ||
func TestValidateConfig(t *testing.T) { | ||
t.Parallel() | ||
|
||
tests := []struct { | ||
desc string | ||
expect error | ||
conf Config | ||
}{ | ||
{ | ||
desc: "Missing valid endpoint", | ||
expect: errMissingEndpointFromConfig, | ||
conf: Config{ | ||
HTTPServerSettings: confighttp.HTTPServerSettings{ | ||
Endpoint: "", | ||
}, | ||
}, | ||
}, | ||
{ | ||
desc: "Valid Secret", | ||
expect: nil, | ||
conf: Config{ | ||
HTTPServerSettings: confighttp.HTTPServerSettings{ | ||
Endpoint: "localhost:8080", | ||
}, | ||
Secret: "mysecret", | ||
}, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.desc, func(t *testing.T) { | ||
err := test.conf.Validate() | ||
if test.expect == nil { | ||
require.NoError(t, err) | ||
require.Equal(t, "mysecret", test.conf.Secret) | ||
} else { | ||
require.Error(t, err) | ||
require.Contains(t, err.Error(), test.expect.Error()) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
t.Parallel() | ||
|
||
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) | ||
require.NoError(t, err) | ||
// LoadConf includes the TypeStr which NewFactory does not set | ||
id := component.NewIDWithName(metadata.Type, "valid_config") | ||
cmNoStr, err := cm.Sub(id.String()) | ||
require.NoError(t, err) | ||
|
||
expect := &Config{ | ||
HTTPServerSettings: confighttp.HTTPServerSettings{ | ||
Endpoint: "localhost:8080", | ||
}, | ||
Path: "/events", | ||
Secret: "mysecret", | ||
} | ||
|
||
// create expected config | ||
factory := NewFactory() | ||
conf := factory.CreateDefaultConfig() | ||
require.NoError(t, component.UnmarshalConfig(cmNoStr, conf)) | ||
require.NoError(t, component.ValidateConfig(conf)) | ||
|
||
require.Equal(t, expect, conf) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
//go:generate mdatagen metadata.yaml | ||
|
||
package githubactionsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubactionsreceiver" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package githubactionsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubactionsreceiver" | ||
|
||
import ( | ||
"context" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
"go.opentelemetry.io/collector/consumer" | ||
"go.opentelemetry.io/collector/receiver" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/githubactionsreceiver/internal/metadata" | ||
) | ||
|
||
// This file implements factory for GitHub Actions receiver. | ||
|
||
const ( | ||
defaultBindEndpoint = "0.0.0.0:19418" | ||
defaultPath = "/ghaevents" | ||
) | ||
|
||
// NewFactory creates a new GitHub Actions receiver factory | ||
func NewFactory() receiver.Factory { | ||
return receiver.NewFactory( | ||
metadata.Type, | ||
createDefaultConfig, | ||
receiver.WithTraces(createTracesReceiver, metadata.TracesStability), | ||
) | ||
} | ||
|
||
// createDefaultConfig creates the default configuration for GitHub Actions receiver. | ||
func createDefaultConfig() component.Config { | ||
return &Config{ | ||
HTTPServerSettings: confighttp.HTTPServerSettings{ | ||
Endpoint: defaultBindEndpoint, | ||
}, | ||
Path: defaultPath, | ||
Secret: "", | ||
} | ||
} | ||
|
||
// createTracesReceiver creates a trace receiver based on provided config. | ||
func createTracesReceiver( | ||
_ context.Context, | ||
set receiver.CreateSettings, | ||
cfg component.Config, | ||
nextConsumer consumer.Traces, | ||
) (receiver.Traces, error) { | ||
rCfg := cfg.(*Config) | ||
return newTracesReceiver(set, rCfg, nextConsumer) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package githubactionsreceiver | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/consumer/consumertest" | ||
"go.opentelemetry.io/collector/receiver/receivertest" | ||
) | ||
|
||
func TestFactoryCreate(t *testing.T) { | ||
factory := NewFactory() | ||
require.EqualValues(t, "githubactions", factory.Type()) | ||
} | ||
|
||
func TestDefaultConfig(t *testing.T) { | ||
cfg := createDefaultConfig() | ||
require.NotNil(t, cfg, "Failed to create default configuration") | ||
} | ||
|
||
func TestCreateTracesReceiver(t *testing.T) { | ||
tests := []struct { | ||
desc string | ||
run func(t *testing.T) | ||
}{ | ||
{ | ||
desc: "Defaults with valid inputs", | ||
run: func(t *testing.T) { | ||
t.Parallel() | ||
|
||
cfg := createDefaultConfig().(*Config) | ||
cfg.Endpoint = "localhost:8080" | ||
require.NoError(t, cfg.Validate(), "error validating default config") | ||
|
||
_, err := createTracesReceiver( | ||
context.Background(), | ||
receivertest.NewNopCreateSettings(), | ||
cfg, | ||
consumertest.NewNop(), | ||
) | ||
require.NoError(t, err, "failed to create trace receiver") | ||
}, | ||
}, | ||
{ | ||
desc: "Missing consumer", | ||
run: func(t *testing.T) { | ||
t.Parallel() | ||
|
||
cfg := createDefaultConfig().(*Config) | ||
cfg.Endpoint = "localhost:8080" | ||
require.NoError(t, cfg.Validate(), "error validating default config") | ||
|
||
_, err := createTracesReceiver( | ||
context.Background(), | ||
receivertest.NewNopCreateSettings(), | ||
cfg, | ||
nil, | ||
) | ||
require.Error(t, err, "Succeeded in creating a receiver without a consumer") | ||
}, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.desc, test.run) | ||
} | ||
} |
Oops, something went wrong.