Skip to content

Commit 4b8775f

Browse files
committed
Merge remote-tracking branch 'origin/main' into ssncferreira/chore-prebuilt-authz-order
2 parents 2c387ce + 7c40f86 commit 4b8775f

File tree

84 files changed

+2456
-751
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+2456
-751
lines changed

.github/.linkspector.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ ignorePatterns:
2424
- pattern: "mutagen.io"
2525
- pattern: "docs.github.com"
2626
- pattern: "claude.ai"
27+
- pattern: "splunk.com"
2728
aliveStatusCodes:
2829
- 200

cli/cliutil/license.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package cliutil
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"time"
7+
8+
"github.com/google/uuid"
9+
"golang.org/x/xerrors"
10+
11+
"github.com/coder/coder/v2/cli/cliui"
12+
"github.com/coder/coder/v2/codersdk"
13+
)
14+
15+
// NewLicenseFormatter returns a new license formatter.
16+
// The formatter will return a table and JSON output.
17+
func NewLicenseFormatter() *cliui.OutputFormatter {
18+
type tableLicense struct {
19+
ID int32 `table:"id,default_sort"`
20+
UUID uuid.UUID `table:"uuid" format:"uuid"`
21+
UploadedAt time.Time `table:"uploaded at" format:"date-time"`
22+
// Features is the formatted string for the license claims.
23+
// Used for the table view.
24+
Features string `table:"features"`
25+
ExpiresAt time.Time `table:"expires at" format:"date-time"`
26+
Trial bool `table:"trial"`
27+
}
28+
29+
return cliui.NewOutputFormatter(
30+
cliui.ChangeFormatterData(
31+
cliui.TableFormat([]tableLicense{}, []string{"ID", "UUID", "Expires At", "Uploaded At", "Features"}),
32+
func(data any) (any, error) {
33+
list, ok := data.([]codersdk.License)
34+
if !ok {
35+
return nil, xerrors.Errorf("invalid data type %T", data)
36+
}
37+
out := make([]tableLicense, 0, len(list))
38+
for _, lic := range list {
39+
var formattedFeatures string
40+
features, err := lic.FeaturesClaims()
41+
if err != nil {
42+
formattedFeatures = xerrors.Errorf("invalid license: %w", err).Error()
43+
} else {
44+
var strs []string
45+
if lic.AllFeaturesClaim() {
46+
// If all features are enabled, just include that
47+
strs = append(strs, "all features")
48+
} else {
49+
for k, v := range features {
50+
if v > 0 {
51+
// Only include claims > 0
52+
strs = append(strs, fmt.Sprintf("%s=%v", k, v))
53+
}
54+
}
55+
}
56+
formattedFeatures = strings.Join(strs, ", ")
57+
}
58+
// If this returns an error, a zero time is returned.
59+
exp, _ := lic.ExpiresAt()
60+
61+
out = append(out, tableLicense{
62+
ID: lic.ID,
63+
UUID: lic.UUID,
64+
UploadedAt: lic.UploadedAt,
65+
Features: formattedFeatures,
66+
ExpiresAt: exp,
67+
Trial: lic.Trial(),
68+
})
69+
}
70+
return out, nil
71+
}),
72+
cliui.ChangeFormatterData(cliui.JSONFormat(), func(data any) (any, error) {
73+
list, ok := data.([]codersdk.License)
74+
if !ok {
75+
return nil, xerrors.Errorf("invalid data type %T", data)
76+
}
77+
for i := range list {
78+
humanExp, err := list[i].ExpiresAt()
79+
if err == nil {
80+
list[i].Claims[codersdk.LicenseExpiryClaim+"_human"] = humanExp.Format(time.RFC3339)
81+
}
82+
}
83+
84+
return list, nil
85+
}),
86+
)
87+
}

cli/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
11251125
autobuildTicker := time.NewTicker(vals.AutobuildPollInterval.Value())
11261126
defer autobuildTicker.Stop()
11271127
autobuildExecutor := autobuild.NewExecutor(
1128-
ctx, options.Database, options.Pubsub, options.PrometheusRegistry, coderAPI.TemplateScheduleStore, &coderAPI.Auditor, coderAPI.AccessControlStore, logger, autobuildTicker.C, options.NotificationsEnqueuer, coderAPI.Experiments)
1128+
ctx, options.Database, options.Pubsub, coderAPI.FileCache, options.PrometheusRegistry, coderAPI.TemplateScheduleStore, &coderAPI.Auditor, coderAPI.AccessControlStore, logger, autobuildTicker.C, options.NotificationsEnqueuer, coderAPI.Experiments)
11291129
autobuildExecutor.Run()
11301130

11311131
jobReaperTicker := time.NewTicker(vals.JobReaperDetectorInterval.Value())

cli/support.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cli
33
import (
44
"archive/zip"
55
"bytes"
6+
"context"
67
"encoding/base64"
78
"encoding/json"
89
"fmt"
@@ -13,6 +14,8 @@ import (
1314
"text/tabwriter"
1415
"time"
1516

17+
"github.com/coder/coder/v2/cli/cliutil"
18+
1619
"github.com/google/uuid"
1720
"golang.org/x/xerrors"
1821

@@ -48,6 +51,7 @@ var supportBundleBlurb = cliui.Bold("This will collect the following information
4851
- Agent details (with environment variable sanitized)
4952
- Agent network diagnostics
5053
- Agent logs
54+
- License status
5155
` + cliui.Bold("Note: ") +
5256
cliui.Wrap("While we try to sanitize sensitive data from support bundles, we cannot guarantee that they do not contain information that you or your organization may consider sensitive.\n") +
5357
cliui.Bold("Please confirm that you will:\n") +
@@ -302,6 +306,11 @@ func writeBundle(src *support.Bundle, dest *zip.Writer) error {
302306
return xerrors.Errorf("decode template zip from base64")
303307
}
304308

309+
licenseStatus, err := humanizeLicenses(src.Deployment.Licenses)
310+
if err != nil {
311+
return xerrors.Errorf("format license status: %w", err)
312+
}
313+
305314
// The below we just write as we have them:
306315
for k, v := range map[string]string{
307316
"agent/logs.txt": string(src.Agent.Logs),
@@ -315,6 +324,7 @@ func writeBundle(src *support.Bundle, dest *zip.Writer) error {
315324
"network/tailnet_debug.html": src.Network.TailnetDebug,
316325
"workspace/build_logs.txt": humanizeBuildLogs(src.Workspace.BuildLogs),
317326
"workspace/template_file.zip": string(templateVersionBytes),
327+
"license-status.txt": licenseStatus,
318328
} {
319329
f, err := dest.Create(k)
320330
if err != nil {
@@ -359,3 +369,13 @@ func humanizeBuildLogs(ls []codersdk.ProvisionerJobLog) string {
359369
_ = tw.Flush()
360370
return buf.String()
361371
}
372+
373+
func humanizeLicenses(licenses []codersdk.License) (string, error) {
374+
formatter := cliutil.NewLicenseFormatter()
375+
376+
if len(licenses) == 0 {
377+
return "No licenses found", nil
378+
}
379+
380+
return formatter.Format(context.Background(), licenses)
381+
}

cli/support_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ func assertBundleContents(t *testing.T, path string, wantWorkspace bool, wantAge
386386
case "cli_logs.txt":
387387
bs := readBytesFromZip(t, f)
388388
require.NotEmpty(t, bs, "CLI logs should not be empty")
389+
case "license-status.txt":
390+
bs := readBytesFromZip(t, f)
391+
require.NotEmpty(t, bs, "license status should not be empty")
389392
default:
390393
require.Failf(t, "unexpected file in bundle", f.Name)
391394
}

coderd/agentapi/subagent.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import (
1212
"golang.org/x/xerrors"
1313

1414
"cdr.dev/slog"
15+
"github.com/coder/quartz"
16+
1517
agentproto "github.com/coder/coder/v2/agent/proto"
1618
"github.com/coder/coder/v2/coderd/database"
1719
"github.com/coder/coder/v2/coderd/database/dbauthz"
1820
"github.com/coder/coder/v2/codersdk"
1921
"github.com/coder/coder/v2/provisioner"
20-
"github.com/coder/quartz"
2122
)
2223

2324
type SubAgentAPI struct {
@@ -164,8 +165,8 @@ func (a *SubAgentAPI) CreateSubAgent(ctx context.Context, req *agentproto.Create
164165
}
165166
}
166167

167-
_, err := a.Database.InsertWorkspaceApp(ctx, database.InsertWorkspaceAppParams{
168-
ID: uuid.New(),
168+
_, err := a.Database.UpsertWorkspaceApp(ctx, database.UpsertWorkspaceAppParams{
169+
ID: uuid.New(), // NOTE: we may need to maintain the app's ID here for stability, but for now we'll leave this as-is.
169170
CreatedAt: createdAt,
170171
AgentID: subAgent.ID,
171172
Slug: app.Slug,

coderd/apidoc/docs.go

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/autobuild/lifecycle_executor.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"golang.org/x/xerrors"
1818

1919
"cdr.dev/slog"
20+
"github.com/coder/coder/v2/coderd/files"
2021

2122
"github.com/coder/coder/v2/coderd/audit"
2223
"github.com/coder/coder/v2/coderd/database"
@@ -35,6 +36,7 @@ type Executor struct {
3536
ctx context.Context
3637
db database.Store
3738
ps pubsub.Pubsub
39+
fileCache *files.Cache
3840
templateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore]
3941
accessControlStore *atomic.Pointer[dbauthz.AccessControlStore]
4042
auditor *atomic.Pointer[audit.Auditor]
@@ -61,13 +63,14 @@ type Stats struct {
6163
}
6264

6365
// New returns a new wsactions executor.
64-
func NewExecutor(ctx context.Context, db database.Store, ps pubsub.Pubsub, reg prometheus.Registerer, tss *atomic.Pointer[schedule.TemplateScheduleStore], auditor *atomic.Pointer[audit.Auditor], acs *atomic.Pointer[dbauthz.AccessControlStore], log slog.Logger, tick <-chan time.Time, enqueuer notifications.Enqueuer, exp codersdk.Experiments) *Executor {
66+
func NewExecutor(ctx context.Context, db database.Store, ps pubsub.Pubsub, fc *files.Cache, reg prometheus.Registerer, tss *atomic.Pointer[schedule.TemplateScheduleStore], auditor *atomic.Pointer[audit.Auditor], acs *atomic.Pointer[dbauthz.AccessControlStore], log slog.Logger, tick <-chan time.Time, enqueuer notifications.Enqueuer, exp codersdk.Experiments) *Executor {
6567
factory := promauto.With(reg)
6668
le := &Executor{
6769
//nolint:gocritic // Autostart has a limited set of permissions.
6870
ctx: dbauthz.AsAutostart(ctx),
6971
db: db,
7072
ps: ps,
73+
fileCache: fc,
7174
templateScheduleStore: tss,
7275
tick: tick,
7376
log: log.Named("autobuild"),
@@ -276,7 +279,7 @@ func (e *Executor) runOnce(t time.Time) Stats {
276279
}
277280
}
278281

279-
nextBuild, job, _, err = builder.Build(e.ctx, tx, nil, audit.WorkspaceBuildBaggage{IP: "127.0.0.1"})
282+
nextBuild, job, _, err = builder.Build(e.ctx, tx, e.fileCache, nil, audit.WorkspaceBuildBaggage{IP: "127.0.0.1"})
280283
if err != nil {
281284
return xerrors.Errorf("build workspace with transition %q: %w", nextTransition, err)
282285
}

coderd/coderd.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ func New(options *Options) *API {
574574
TemplateScheduleStore: options.TemplateScheduleStore,
575575
UserQuietHoursScheduleStore: options.UserQuietHoursScheduleStore,
576576
AccessControlStore: options.AccessControlStore,
577-
FileCache: files.NewFromStore(options.Database, options.PrometheusRegistry, options.Authorizer),
577+
FileCache: files.New(options.PrometheusRegistry, options.Authorizer),
578578
Experiments: experiments,
579579
WebpushDispatcher: options.WebPushDispatcher,
580580
healthCheckGroup: &singleflight.Group[string, *healthsdk.HealthcheckReport]{},
@@ -972,7 +972,7 @@ func New(options *Options) *API {
972972
})
973973
r.Route("/experiments", func(r chi.Router) {
974974
r.Use(apiKeyMiddleware)
975-
r.Get("/available", handleExperimentsSafe)
975+
r.Get("/available", handleExperimentsAvailable)
976976
r.Get("/", api.handleExperimentsGet)
977977
})
978978
r.Get("/updatecheck", api.updateCheck)
@@ -1895,7 +1895,9 @@ func ReadExperiments(log slog.Logger, raw []string) codersdk.Experiments {
18951895
exps = append(exps, codersdk.ExperimentsSafe...)
18961896
default:
18971897
ex := codersdk.Experiment(strings.ToLower(v))
1898-
if !slice.Contains(codersdk.ExperimentsSafe, ex) {
1898+
if !slice.Contains(codersdk.ExperimentsKnown, ex) {
1899+
log.Warn(context.Background(), "ignoring unknown experiment", slog.F("experiment", ex))
1900+
} else if !slice.Contains(codersdk.ExperimentsSafe, ex) {
18991901
log.Warn(context.Background(), "🐉 HERE BE DRAGONS: opting into hidden experiment", slog.F("experiment", ex))
19001902
}
19011903
exps = append(exps, ex)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy