Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Webhooks #1365

Merged
merged 58 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
54d1031
Webhook Feature implementation
andreas-marschke Jul 2, 2023
0443699
Include slices
andreas-marschke Dec 2, 2023
7fd87d7
go.sum addition
andreas-marschke Dec 2, 2023
8d0e39b
Fix method calls, add is null for globals
andreas-marschke Dec 2, 2023
055ecb8
Remove dead code and unused dependency
andreas-marschke Jan 3, 2024
183a853
Fix param reception
andreas-marschke Jan 4, 2024
4f4d8c5
Polish UI to allow crumb-style navigation
andreas-marschke Jan 8, 2024
203b169
Fixup api
andreas-marschke Jan 8, 2024
d2a5266
Fix error message string composition
andreas-marschke Jan 8, 2024
7e0d564
Clean up logging in backend
andreas-marschke Jan 8, 2024
d09f416
Undo changes to getObject calls in sql
andreas-marschke Jan 10, 2024
03c894d
Updating API to support projectID attachment
andreas-marschke Jan 10, 2024
c54a03d
Update Dredd Code to support webhooks
andreas-marschke Jan 11, 2024
fe83cef
Update Dredd changes
andreas-marschke Jan 15, 2024
a4406b7
Add Extractor capability
andreas-marschke Jan 15, 2024
fc4925d
Fix hook string
andreas-marschke Jan 15, 2024
ffad5d4
Add Hooks for extractors
andreas-marschke Jan 15, 2024
a1ec242
extend Regex to support deep representation of webhook REST API
andreas-marschke Jan 15, 2024
b1177a2
Try to make Webhook API more consistent
andreas-marschke Feb 10, 2024
647501b
refactor: webhook -> integration
fiftin Feb 11, 2024
d877277
fix(webhooks): merge conflict
fiftin Feb 11, 2024
2215fb5
fix(webhooks): merge conflict
fiftin Feb 11, 2024
ae20f7b
fix(runners): return webhook name
fiftin Feb 11, 2024
3d818ea
fix(slack): return webhook in text
fiftin Feb 11, 2024
6976b2a
fix(runners): return webhook name
fiftin Feb 11, 2024
8358fee
fix(runners): return webhook name
fiftin Feb 11, 2024
006d14a
refactor(integrations): rename files
fiftin Feb 11, 2024
a6e541e
Merge branch 'feat-support-integrations' into feat-support-webhooks
fiftin Feb 11, 2024
d434909
fix(integrations): return code deleted by mistake due to a merge conf…
fiftin Feb 11, 2024
75d59d0
fix(integrations): route and sql
fiftin Feb 11, 2024
6957f45
fix(integrations): params order
fiftin Feb 11, 2024
aba28b9
feat(integrations): change icon
fiftin Feb 12, 2024
3a821b5
feat(integrations): add auth fields to db
fiftin Feb 12, 2024
c9788f1
feat(integration): add auth header
fiftin Feb 12, 2024
39ad2c9
feat(integrations): add hmac verification method
fiftin Feb 12, 2024
ce757f3
feat(integrations): use verification
fiftin Feb 12, 2024
2513768
fix: merge conflict
fiftin Mar 3, 2024
06cf907
feat: integration tests
fiftin Mar 3, 2024
fc8baea
fix: tests for integrations
fiftin Mar 3, 2024
88ef65a
feat(integrations): use only explicit intergations
fiftin Mar 3, 2024
a5055ff
fix(integrations): refs
fiftin Mar 3, 2024
f3c17a3
ci: white unlil db started
fiftin Mar 3, 2024
cfcfc8e
fix(integrations): escape pg keyword
fiftin Mar 3, 2024
ffdf818
fix(integrations): sql query
fiftin Mar 3, 2024
e8973fd
Merge branch 'develop' into feat-support-webhooks
fiftin Mar 4, 2024
1ef9012
feat(integrations): add param
fiftin Mar 4, 2024
582a3c9
feat(integrations): add project param
fiftin Mar 4, 2024
09a37ee
feat(integrations): use project id
fiftin Mar 4, 2024
f4a54d9
feat: use project id
fiftin Mar 4, 2024
fac4420
refactor(integrations): remove extra code
fiftin Mar 4, 2024
bf20ffb
feat(bolt): use project id
fiftin Mar 4, 2024
7b6394a
chore(bolt): fix integrations
fiftin Mar 4, 2024
e944cf2
fix(integration): return correct value list
fiftin Mar 4, 2024
b1ce6d1
fix(integrations): project id
fiftin Mar 4, 2024
3f73cc7
fix(integration): project id 0
fiftin Mar 4, 2024
7cd250d
fix(integrations): correct extractor list
fiftin Mar 4, 2024
50615d0
test: inject id
fiftin Mar 4, 2024
44e45c1
test: return put for extractors
fiftin Mar 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 58 additions & 12 deletions .dredd/hooks/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package main

import (
"encoding/json"
"github.com/ansible-semaphore/semaphore/db"
trans "github.com/snikch/goodman/transaction"
"regexp"
"strconv"
"strings"

"github.com/ansible-semaphore/semaphore/db"
trans "github.com/snikch/goodman/transaction"
)

// STATE
Expand All @@ -18,23 +19,35 @@ var userKey *db.AccessKey
var task *db.Task
var schedule *db.Schedule
var view *db.View
var integration *db.Integration
var integrationextractor *db.IntegrationExtractor
var integrationextractvalue *db.IntegrationExtractValue
var integrationmatch *db.IntegrationMatcher

// Runtime created simple ID values for some items we need to reference in other objects
var repoID int
var inventoryID int
var environmentID int
var templateID int
var integrationID int
var integrationExtractorID int
var integrationExtractValueID int
var integrationMatchID int

var capabilities = map[string][]string{
"user": {},
"project": {"user"},
"repository": {"access_key"},
"inventory": {"repository"},
"environment": {"repository"},
"template": {"repository", "inventory", "environment", "view"},
"task": {"template"},
"schedule": {"template"},
"view": {},
"user": {},
"project": {"user"},
"repository": {"access_key"},
"inventory": {"repository"},
"environment": {"repository"},
"template": {"repository", "inventory", "environment", "view"},
"task": {"template"},
"schedule": {"template"},
"view": {},
"integration": {"project", "template"},
"integrationextractor": {"integration"},
"integrationextractvalue": {"integrationextractor"},
"integrationmatcher": {"integrationextractor"},
}

func capabilityWrapper(cap string) func(t *trans.Transaction) {
Expand Down Expand Up @@ -131,6 +144,18 @@ func resolveCapability(caps []string, resolved []string, uid string) {
templateID = res.ID
case "task":
task = addTask()
case "integration":
integration = addIntegration()
integrationID = integration.ID
case "integrationextractor":
integrationextractor = addIntegrationExtractor()
integrationExtractorID = integrationextractor.ID
case "integrationextractvalue":
integrationextractvalue = addIntegrationExtractValue()
integrationExtractValueID = integrationextractvalue.ID
case "integrationmatcher":
integrationmatch = addIntegrationMatcher()
integrationMatchID = integrationmatch.ID
default:
panic("unknown capability " + v)
}
Expand All @@ -157,6 +182,10 @@ var pathSubPatterns = []func() string{
func() string { return strconv.Itoa(task.ID) },
func() string { return strconv.Itoa(schedule.ID) },
func() string { return strconv.Itoa(view.ID) },
func() string { return strconv.Itoa(integration.ID) },
func() string { return strconv.Itoa(integrationextractor.ID) },
func() string { return strconv.Itoa(integrationextractvalue.ID) },
func() string { return strconv.Itoa(integrationmatch.ID) },
}

// alterRequestPath with the above slice of functions
Expand All @@ -165,12 +194,14 @@ func alterRequestPath(t *trans.Transaction) {
exploded := make([]string, len(pathArgs))
copy(exploded, pathArgs)
for k, v := range pathSubPatterns {

pos, exists := stringInSlice(strconv.Itoa(k+1), exploded)
if exists {
pathArgs[pos] = v()
}
}
t.FullPath = strings.Join(pathArgs, "/")

t.Request.URI = t.FullPath
}

Expand Down Expand Up @@ -198,9 +229,24 @@ func alterRequestBody(t *trans.Transaction) {
if view != nil {
bodyFieldProcessor("view_id", view.ID, &request)
}

if integration != nil {
bodyFieldProcessor("integration_id", integration.ID, &request)
}
if integrationextractor != nil {
bodyFieldProcessor("extractor_id", integrationextractor.ID, &request)
}
if integrationextractvalue != nil {
bodyFieldProcessor("value_id", integrationextractvalue.ID, &request)
}
if integrationmatch != nil {
bodyFieldProcessor("matcher_id", integrationmatch.ID, &request)
}

// Inject object ID to body for PUT requests
if strings.ToLower(t.Request.Method) == "put" {
putRequestPathRE := regexp.MustCompile(`/api/(?:project/\d+/)?\w+/(\d+)/?$`)

putRequestPathRE := regexp.MustCompile(`\w+/(\d+)/?$`)
m := putRequestPathRE.FindStringSubmatch(t.FullPath)
if len(m) > 0 {
objectID, err := strconv.Atoi(m[1])
Expand Down
72 changes: 69 additions & 3 deletions .dredd/hooks/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ package main
import (
"encoding/json"
"fmt"
"math/rand"
"os"
"time"

"github.com/ansible-semaphore/semaphore/db"
"github.com/ansible-semaphore/semaphore/db/bolt"
"github.com/ansible-semaphore/semaphore/db/factory"
"github.com/ansible-semaphore/semaphore/db/sql"
"github.com/ansible-semaphore/semaphore/util"
"github.com/go-gorp/gorp/v3"
"github.com/snikch/goodman/transaction"
"math/rand"
"os"
"time"
)

// Test Runner User
Expand Down Expand Up @@ -59,6 +60,10 @@ func truncateAll() {
"project__user",
"user",
"project__view",
"project__integration",
"project__integration_extractor",
"project__integration_extract_value",
"project__integration_matcher",
}

switch store.(type) {
Expand Down Expand Up @@ -225,6 +230,67 @@ func addTask() *db.Task {
return &t
}

func addIntegration() *db.Integration {
integration, err := store.CreateIntegration(db.Integration{
ProjectID: userProject.ID,
Name: "Test Integration",
TemplateID: templateID,
})
if err != nil {
panic(err)
}

return &integration
}

func addIntegrationExtractor() *db.IntegrationExtractor {
integrationextractor, err := store.CreateIntegrationExtractor(userProject.ID, db.IntegrationExtractor{
IntegrationID: integrationID,
Name: "Integration Extractor",
})

if err != nil {
panic(err)
}

return &integrationextractor
}

func addIntegrationExtractValue() *db.IntegrationExtractValue {
integrationextractvalue, err := store.CreateIntegrationExtractValue(userProject.ID, db.IntegrationExtractValue{
Name: "Value",
ExtractorID: integrationExtractorID,
ValueSource: db.IntegrationExtractBodyValue,
BodyDataType: db.IntegrationBodyDataJSON,
Key: "key",
Variable: "var",
})

if err != nil {
panic(err)
}

return &integrationextractvalue
}

func addIntegrationMatcher() *db.IntegrationMatcher {
integrationmatch, err := store.CreateIntegrationMatcher(userProject.ID, db.IntegrationMatcher{
Name: "matcher",
ExtractorID: integrationExtractorID,
MatchType: "body",
Method: "equals",
BodyDataType: "json",
Key: "key",
Value: "value",
})

if err != nil {
panic(err)
}

return &integrationmatch
}

// Token Handling
func addToken(tok string, user int) {
_, err := store.CreateAPIToken(db.APIToken{
Expand Down
19 changes: 19 additions & 0 deletions .dredd/hooks/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func main() {
defer store.Close("")
addToken(expiredToken, testRunnerUser.ID)
})

h.After("user > /api/user/tokens/{api_token_id} > Expires API token > 204 > application/json", func(transaction *trans.Transaction) {
dbConnect()
defer store.Close("")
Expand All @@ -78,6 +79,24 @@ func main() {
transaction.Request.Body = "{ \"user_id\": " + strconv.Itoa(userPathTestUser.ID) + ",\"role\": \"owner\"}"
})

h.Before("project > /api/project/{project_id}/integrations > get all integrations > 200 > application/json", capabilityWrapper("integration"))
h.Before("project > /api/project/{project_id}/integrations/{integration_id} > Get Integration > 200 > application/json", capabilityWrapper("integration"))
h.Before("project > /api/project/{project_id}/integrations/{integration_id} > Update Integration > 204 > application/json", capabilityWrapper("integration"))
h.Before("project > /api/project/{project_id}/integrations/{integration_id} > Remove integration > 204 > application/json", capabilityWrapper("integration"))

h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors > Get Integration Extractors > 200 > application/json", capabilityWrapper("integrationextractor"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors > Add Integration Extractor > 201 > application/json", capabilityWrapper("integration"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id} > Updates Integration extractor > 204 > application/json", capabilityWrapper("integrationextractor"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id} > Removes integration extractor > 204 > application/json", capabilityWrapper("integrationextractor"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/values > Get Integration Extracted Values linked to integration extractor > 200 > application/json", capabilityWrapper("integrationextractvalue"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/values > Add Integration Extracted Value > 204 > application/json", capabilityWrapper("integrationextractvalue"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/values/{extractvalue_id} > Removes integration extract value > 204 > application/json", capabilityWrapper("integrationextractvalue"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/values > Add Integration Extracted Value > 204 > application/json", capabilityWrapper("integrationextractor"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/values/{extractvalue_id} > Updates Integration ExtractValue > 204 > application/json", capabilityWrapper("integrationextractvalue"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/matchers > Get Integration Matcher linked to integration extractor > 200 > application/json", capabilityWrapper("integrationextractor"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/matchers > Add Integration Matcher > 204 > application/json", capabilityWrapper("integrationextractor"))
h.Before("integration > /api/project/{project_id}/integrations/{integration_id}/extractors/{extractor_id}/matchers/{matcher_id} > Updates Integration Matcher > 204 > application/json", capabilityWrapper("integrationmatcher"))

h.Before("project > /api/project/{project_id}/keys/{key_id} > Updates access key > 204 > application/json", capabilityWrapper("access_key"))
h.Before("project > /api/project/{project_id}/keys/{key_id} > Removes access key > 204 > application/json", capabilityWrapper("access_key"))

Expand Down
14 changes: 8 additions & 6 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,21 @@ jobs:
with:
name: semaphore

- run: "cat > config.json <<EOF\n{\n\t\"postgres\": {\n\t\t\"host\": \"127.0.0.1:5432\"\
,\n\t\t\"options\":{\"sslmode\":\"disable\"}\
,\n\t\t\"user\": \"root\",\n\t\t\"pass\": \"pwd\",\n\t\t\"name\": \"circle_test\"\
\n\t},\n\t\"dialect\": \"postgres\",\n\t\"email_alert\": false\n}\nEOF\n"

- run: chmod +x ./semaphore && ./semaphore migrate --config config.json
- run: sleep 5

- run: "cat > config.json <<EOF\n{\n\t\"mysql\": {\n\t\t\"host\": \"127.0.0.1:3306\"\
,\n\t\t\"user\": \"root\",\n\t\t\"pass\": \"\",\n\t\t\"name\": \"circle_test\"\
\n\t},\n\t\"dialect\": \"mysql\",\n\t\"email_alert\": false\n}\nEOF\n"

- run: chmod +x ./semaphore && ./semaphore migrate --config config.json

- run: "cat > config.json <<EOF\n{\n\t\"postgres\": {\n\t\t\"host\": \"127.0.0.1:5432\"\
,\n\t\t\"options\":{\"sslmode\":\"disable\"}\
,\n\t\t\"user\": \"root\",\n\t\t\"pass\": \"pwd\",\n\t\t\"name\": \"circle_test\"\
\n\t},\n\t\"dialect\": \"postgres\",\n\t\"email_alert\": false\n}\nEOF\n"

- run: chmod +x ./semaphore && ./semaphore migrate --config config.json

- run: "cat > config.json <<EOF\n{\n\t\"bolt\": {\n\t\t\"host\": \"/tmp/database.bolt\"\
\n\t},\n\t\"dialect\": \"bolt\",\n\t\"email_alert\": false\n}\nEOF\n"

Expand Down
Loading
Loading