plan --check treated BotFather profile reassertion as drift, so a scheduled check could never go quiet. Reassertion is now its own kind; a changed spec digest is the drift signal. apply reasserts the profile, updates channel copy when the spec changes, and is tested against a fake Telegram surface. The adapter reads its chat id from resolved state and its token from OpenBao, never the operator session. IEI-2 records that an approved provisioning plan is not autonomous Daimon action. Assistant: grok Assistant-Session: 01a09d5a-92c1-7802-915b-92bee57fc9f0
114 lines
3.4 KiB
Go
114 lines
3.4 KiB
Go
package adaptercfg
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/tegwick/fluid-telegram/internal/secrets"
|
|
"github.com/tegwick/fluid-telegram/internal/spec"
|
|
"github.com/tegwick/fluid-telegram/internal/state"
|
|
)
|
|
|
|
func provisioned() *state.Resolved {
|
|
now := time.Now()
|
|
return &state.Resolved{
|
|
Campaign: "hall-of-helix",
|
|
Bot: state.Bot{Username: "HelixForgeBot", ID: 42},
|
|
Channels: map[string]state.Channel{
|
|
spec.Test: {ChatID: -1001, AdminRights: []string{spec.PostMessages}, TestPublicationAt: &now},
|
|
spec.Live: {ChatID: -2002, Username: "hallofhelix", AdminRights: []string{spec.PostMessages}},
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestFromResolvedPicksOneChannel(t *testing.T) {
|
|
cfg, err := FromResolved(provisioned(), spec.Test, "bao:platform/x/bot-token")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if cfg.ChatID != -1001 || cfg.Channel != spec.Test {
|
|
t.Fatalf("got %+v", cfg)
|
|
}
|
|
cfg, err = FromResolved(provisioned(), spec.Live, "bao:platform/x/bot-token")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if cfg.ChatID != -2002 {
|
|
t.Fatalf("public chat id = %d", cfg.ChatID)
|
|
}
|
|
}
|
|
|
|
func TestFromResolvedRefusesUnprovisioned(t *testing.T) {
|
|
if _, err := FromResolved(&state.Resolved{}, spec.Test, "ref"); err == nil {
|
|
t.Fatal("accepted an empty state")
|
|
}
|
|
rs := provisioned()
|
|
delete(rs.Channels, spec.Live)
|
|
rs.Channels[spec.Test] = state.Channel{ChatID: -1001, AdminRights: []string{spec.PostMessages}}
|
|
if _, err := FromResolved(rs, spec.Live, "ref"); err == nil {
|
|
t.Fatal("accepted a public channel that has not been provisioned")
|
|
}
|
|
}
|
|
|
|
func TestEnvFileHasNoToken(t *testing.T) {
|
|
cfg, _ := FromResolved(provisioned(), spec.Test, "bao:platform/x/bot-token")
|
|
out := cfg.EnvFile()
|
|
for _, line := range strings.Split(out, "\n") {
|
|
if strings.HasPrefix(line, "TELEGRAM_BOT_TOKEN=") {
|
|
t.Fatal("env file emitted a token value")
|
|
}
|
|
}
|
|
if !strings.Contains(out, "TELEGRAM_CHANNEL_ID=-1001") {
|
|
t.Fatalf("missing chat id:\n%s", out)
|
|
}
|
|
if !strings.Contains(out, "TELEGRAM_BOT_TOKEN_REF=bao:platform/x/bot-token") {
|
|
t.Fatalf("missing token ref:\n%s", out)
|
|
}
|
|
if strings.Contains(out, "operator-session") {
|
|
t.Fatal("adapter config mentioned the operator session")
|
|
}
|
|
}
|
|
|
|
func TestLoadTokenReadsOnlyTheBotToken(t *testing.T) {
|
|
var requested []string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
requested = append(requested, r.URL.Path)
|
|
if strings.Contains(r.URL.Path, secrets.KeyOperatorSession) {
|
|
t.Errorf("adapter requested the operator session: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusForbidden)
|
|
return
|
|
}
|
|
if !strings.HasSuffix(r.URL.Path, "/"+secrets.KeyBotToken) {
|
|
t.Errorf("unexpected path %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"data": map[string]any{"data": map[string]string{"token": "123:abc"}},
|
|
})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
t.Setenv("BAO_ADDR", srv.URL)
|
|
t.Setenv("BAO_TOKEN", "test-token")
|
|
store, err := secrets.NewFromEnv("hall-of-helix")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := LoadToken(context.Background(), store)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "123:abc" {
|
|
t.Fatalf("token = %q", got)
|
|
}
|
|
for _, p := range requested {
|
|
if strings.Contains(p, secrets.KeyOperatorSession) || strings.Contains(p, secrets.KeyOperatorApp) {
|
|
t.Fatalf("adapter store was asked for %s", p)
|
|
}
|
|
}
|
|
}
|