Skip to content

Commit 25ad5a4

Browse files
authored
Merge pull request #11 from stgraber/main
Add source field for flag submissions
2 parents bcc9426 + c6c2c07 commit 25ad5a4

21 files changed

Lines changed: 511 additions & 32 deletions

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ FROM golang:latest AS builder
22
WORKDIR /src
33
COPY go.mod go.sum ./
44
RUN go mod download
5+
RUN apt-get update && apt-get install -y make
56
COPY . .
6-
RUN apt-get update && apt-get install -y make && make linux
7+
RUN make linux
78

89
FROM debian:bookworm-slim
910
COPY --from=builder /src/bin/linux/askgod-server /askgod-server

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,10 @@ This will create two executables in `./bin/linux`: `askgod` and `askgod-server`.
4747

4848
```bash
4949
./bin/linux/askgod-server ./askgod.yaml.example
50-
```
50+
```
51+
52+
## MCP Server
53+
54+
The askgod server supports an MCP server at `<askgod_server_address>/mcp`.
55+
This MCP server allows users to submit flags.
56+
The MCP Server is disabled by default, but can be enabled by setting `mcp: true` in the config.

api/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type Config struct {
99

1010
Daemon ConfigDaemon `json:"daemon" yaml:"daemon"`
1111
Database ConfigDatabase `json:"database" yaml:"database"`
12+
MCP bool `json:"mcp" yaml:"mcp"`
1213
}
1314

1415
// ConfigPut represents the editable Askgod configuration.

api/flag.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,47 @@
11
package api
22

33
import (
4+
"slices"
45
"time"
56
)
67

8+
// Valid values for the Source field on flag and score entries.
9+
const (
10+
SourceUnknown = "unknown"
11+
SourceCLI = "cli"
12+
SourceCLIAgent = "cli+agent"
13+
SourceMCP = "mcp"
14+
SourceWeb = "web"
15+
SourceWebAgent = "web+agent"
16+
)
17+
18+
// validSources lists every accepted Source value (excluding the empty string,
19+
// which is normalized to SourceUnknown by NormalizeSource).
20+
var validSources = []string{
21+
SourceUnknown,
22+
SourceCLI,
23+
SourceCLIAgent,
24+
SourceMCP,
25+
SourceWeb,
26+
SourceWebAgent,
27+
}
28+
29+
// NormalizeSource validates the provided source and returns the canonical
30+
// value to store. An empty source is translated to SourceUnknown for
31+
// compatibility with older clients. The returned bool indicates whether the
32+
// input was a recognized value.
33+
func NormalizeSource(source string) (string, bool) {
34+
if source == "" {
35+
return SourceUnknown, true
36+
}
37+
38+
if slices.Contains(validSources, source) {
39+
return source, true
40+
}
41+
42+
return source, false
43+
}
44+
745
// URL: /1.0/team/flags
846
// Access: team
947

@@ -15,6 +53,7 @@ type Flag struct {
1553
Description string `json:"description" yaml:"description"`
1654
ReturnString string `json:"return_string" yaml:"return_string"`
1755
Value int64 `json:"value" yaml:"value"`
56+
Source string `json:"source" yaml:"source"`
1857
SubmitTime time.Time `json:"submit_time" yaml:"submit_time"`
1958
}
2059

@@ -24,10 +63,19 @@ type FlagPut struct {
2463
}
2564

2665
// FlagPost represents the fields used to submit a new score entry.
66+
//
67+
// Source tracks where the flag submission came from. Valid values are:
68+
// - "" => compatibility mechanism, translated to "unknown" internally
69+
// - "cli" => human submission through CLI
70+
// - "cli+agent" => agent submission through CLI
71+
// - "mcp" => submitted through the MCP server
72+
// - "web" => human submission through website
73+
// - "web+agent" => agent submission through website
2774
type FlagPost struct {
2875
FlagPut `yaml:",inline"`
2976

30-
Flag string `json:"flag" yaml:"flag"`
77+
Flag string `json:"flag" yaml:"flag"`
78+
Source string `json:"source" yaml:"source"`
3179
}
3280

3381
// URL: /1.0/flags

api/score.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type AdminScorePut struct {
2525
type AdminScorePost struct {
2626
AdminScorePut `yaml:",inline"`
2727

28-
TeamID int64 `json:"team_id" yaml:"team_id"`
29-
FlagID int64 `json:"flag_id" yaml:"flag_id"`
28+
TeamID int64 `json:"team_id" yaml:"team_id"`
29+
FlagID int64 `json:"flag_id" yaml:"flag_id"`
30+
Source string `json:"source" yaml:"source"`
3031
}

askgod.yaml.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,6 @@ subnets:
9595
guests:
9696
- ::/0
9797
- 0.0.0.0/0
98+
99+
# Enable or disable the MCP server. Defaults to false.
100+
mcp: true

cmd/askgod/cmd_admin_score.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (c *client) cmdAdminListScores(ctx context.Context, _ *cli.Command) error {
110110
const layout = "2006/01/02 15:04"
111111

112112
table := tablewriter.NewWriter(os.Stdout)
113-
table.SetHeader([]string{"ID", "TeamID", "FlagID", "Value", "Submit time", "Notes"})
113+
table.SetHeader([]string{"ID", "TeamID", "FlagID", "Value", "Submit time", "Source", "Notes"})
114114
table.SetBorder(false)
115115
table.SetAutoWrapText(false)
116116

@@ -121,6 +121,7 @@ func (c *client) cmdAdminListScores(ctx context.Context, _ *cli.Command) error {
121121
strconv.FormatInt(entry.FlagID, 10),
122122
strconv.FormatInt(entry.Value, 10),
123123
entry.SubmitTime.Local().Format(layout),
124+
entry.Source,
124125
entry.Notes,
125126
})
126127
}

cmd/askgod/cmd_history.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (c *client) cmdHistory(ctx context.Context, cmd *cli.Command) error {
5050
const layout = "2006/01/02 15:04"
5151

5252
table := tablewriter.NewWriter(os.Stdout)
53-
table.SetHeader([]string{"ID", "Description", "Value", "Timestamp", "Message", "Notes"})
53+
table.SetHeader([]string{"ID", "Description", "Value", "Timestamp", "Source", "Message", "Notes"})
5454
table.SetBorder(false)
5555
table.SetAutoWrapText(false)
5656

@@ -60,6 +60,7 @@ func (c *client) cmdHistory(ctx context.Context, cmd *cli.Command) error {
6060
flag.Description,
6161
strconv.FormatInt(flag.Value, 10),
6262
flag.SubmitTime.Local().Format(layout),
63+
flag.Source,
6364
flag.ReturnString,
6465
flag.Notes,
6566
})

cmd/askgod/cmd_submit.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,34 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"os"
67

78
"github.com/urfave/cli/v3"
89

910
"github.com/nsec/askgod/api"
1011
)
1112

13+
func hasAgentInEnvVariable() bool {
14+
for _, env := range []string{
15+
"AGENT",
16+
"ANTIGRAVITY_AGENT",
17+
"CLAUDECODE",
18+
"CLAUDE_CODE_IS_COWORK",
19+
"CLINE_ACTIVE",
20+
"CODEX_SHELL",
21+
"CURSOR_AGENT",
22+
"GEMINI_CLI",
23+
"OPENCODE",
24+
"WINDSURF_CASCADE_TERMINAL_KIND",
25+
} {
26+
if os.Getenv(env) != "" {
27+
return true
28+
}
29+
}
30+
31+
return false
32+
}
33+
1234
func (c *client) cmdSubmit(ctx context.Context, cmd *cli.Command) error {
1335
if cmd.NArg() != 1 {
1436
_ = cli.ShowCommandHelp(ctx, cmd, "submit")
@@ -21,6 +43,22 @@ func (c *client) cmdSubmit(ctx context.Context, cmd *cli.Command) error {
2143
flag.Flag = cmd.Args().Get(0)
2244
flag.Notes = cmd.String("notes")
2345

46+
// Determine whether the submission was AI-assisted using a tri-state flag:
47+
// --agent forces on, --agent=false forces off, otherwise autodetect from env.
48+
var agent bool
49+
if cmd.IsSet("agent") {
50+
agent = cmd.Bool("agent")
51+
} else {
52+
agent = hasAgentInEnvVariable()
53+
}
54+
55+
flag.Source = api.SourceCLI
56+
if agent {
57+
flag.Source = api.SourceCLIAgent
58+
59+
_, _ = fmt.Print("Note: This flag submission is marked as AI-assisted.\n") //nolint:forbidigo
60+
}
61+
2462
// Send the flag
2563
resp := api.Flag{}
2664

cmd/askgod/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ func main() {
231231
Name: "notes",
232232
Usage: "Some notes to remind you of the flag",
233233
},
234+
&cli.BoolFlag{
235+
Name: "agent",
236+
Usage: "Override AI agent autodetection (--agent to force on, --agent=false to force off)",
237+
},
234238
},
235239
Action: c.cmdSubmit,
236240
},

0 commit comments

Comments
 (0)