Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion api/api/versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"version": "v1",
"status": "active",
"release_date": "2025-08-28T18:36:20.486085+05:30",
"release_date": "2025-08-30T15:18:20.306258+05:30",
"end_of_life": "0001-01-01T00:00:00Z",
"changes": [
"Initial API version"
Expand Down
2 changes: 1 addition & 1 deletion api/doc/openapi.json

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ require (
github.com/moby/term v0.5.2
github.com/opencontainers/image-spec v1.1.1
github.com/pkg/sftp v1.13.7
github.com/shirou/gopsutil/v3 v3.24.5
github.com/sirupsen/logrus v1.9.3
github.com/slack-go/slack v0.16.0
github.com/spf13/viper v1.20.1
Expand Down Expand Up @@ -54,7 +53,6 @@ require (
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/jsonpointer v0.21.1 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
Expand All @@ -78,7 +76,6 @@ require (
github.com/klauspost/compress v1.18.0 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lunixbochs/vtclean v1.0.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
Expand All @@ -101,24 +98,19 @@ require (
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
Expand Down
21 changes: 0 additions & 21 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
Expand Down Expand Up @@ -158,8 +156,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
Expand Down Expand Up @@ -227,20 +223,12 @@ github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3D
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/slack-go/slack v0.16.0 h1:khp/WCFv+Hb/B/AJaAwvcxKun0hM6grN0bUZ8xG60P8=
Expand Down Expand Up @@ -275,10 +263,6 @@ github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX2
github.com/thejerf/slogassert v0.3.4/go.mod h1:0zn9ISLVKo1aPMTqcGfG1o6dWwt+Rk574GlUxHD4rs8=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/traefik/yaegi v0.9.8/go.mod h1:FAYnRlZyuVlEkvnkHq3bvJ1lW5be6XuwgLdkYgYG6Lk=
Expand Down Expand Up @@ -306,8 +290,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
Expand Down Expand Up @@ -379,7 +361,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -388,7 +369,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -404,7 +384,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
Expand Down
10 changes: 9 additions & 1 deletion api/internal/features/container/controller/get_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ import (
func (c *ContainerController) GetContainer(f fuego.ContextNoBody) (*shared_types.Response, error) {
containerID := f.PathParam("container_id")

containerInfo, err := c.dockerService.GetContainerById(containerID)
dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()
containerInfo, err := dockerService.GetContainerById(containerID)
if err != nil {
c.logger.Log(logger.Error, err.Error(), "")
return nil, fuego.HTTPError{
Expand Down
11 changes: 10 additions & 1 deletion api/internal/features/container/controller/get_container_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ func (c *ContainerController) GetContainerLogs(f fuego.ContextWithBody[types.Con
}
}

logsReader, err := c.dockerService.GetContainerLogs(req.ID, container.LogsOptions{
dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()

logsReader, err := dockerService.GetContainerLogs(req.ID, container.LogsOptions{
Follow: req.Follow,
Tail: strconv.Itoa(req.Tail),
Since: req.Since,
Expand Down
65 changes: 40 additions & 25 deletions api/internal/features/container/controller/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ import (
)

type ContainerController struct {
store *shared_storage.Store
dockerService *docker.DockerService
ctx context.Context
logger logger.Logger
notification *notification.NotificationManager
store *shared_storage.Store
ctx context.Context
logger logger.Logger
notification *notification.NotificationManager
}

func NewContainerController(
Expand All @@ -27,27 +26,43 @@ func NewContainerController(
notificationManager *notification.NotificationManager,
) *ContainerController {
return &ContainerController{
store: store,
dockerService: docker.NewDockerService(),
ctx: ctx,
logger: l,
notification: notificationManager,
store: store,
ctx: ctx,
logger: l,
notification: notificationManager,
}
}

func (c *ContainerController) isProtectedContainer(containerID string, action string) (*shared_types.Response, bool) {
details, err := c.dockerService.GetContainerById(containerID)
if err != nil {
return nil, false
}
name := strings.ToLower(details.Name)
if strings.Contains(name, "nixopus") {
c.logger.Log(logger.Info, fmt.Sprintf("Skipping %s for protected container", action), details.Name)
return &shared_types.Response{
Status: "success",
Message: "Operation skipped for protected container",
Data: map[string]string{"status": "skipped"},
}, true
}
return nil, false
// getDockerService creates a Docker service based on the request context
// If a server is in the context, it will use SSH tunnel, otherwise local connection
func (c *ContainerController) getDockerService(ctx context.Context) (*docker.DockerService, error) {
dockerService, err := docker.NewDockerServiceWithContext(ctx)
if err != nil {
c.logger.Log(logger.Error, "Failed to create Docker service with context", err.Error())
return docker.NewDockerService(), nil
}
return dockerService, nil
}
Comment on lines +36 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not silently fall back to local Docker on context failure

Falling back to a local Docker client can target the wrong host, risking unintended mutations. Prefer propagating the error; callers can decide behavior.

Apply this diff:

 func (c *ContainerController) getDockerService(ctx context.Context) (*docker.DockerService, error) {
   dockerService, err := docker.NewDockerServiceWithContext(ctx)
   if err != nil {
-    c.logger.Log(logger.Error, "Failed to create Docker service with context", err.Error())
-    return docker.NewDockerService(), nil
+    c.logger.Log(logger.Error, "Failed to create Docker service with context", err.Error())
+    return nil, err
   }
   return dockerService, nil
 }
🤖 Prompt for AI Agents
In api/internal/features/container/controller/init.go around lines 36 to 45, the
function currently logs the context creation error and silently returns a local
DockerService, which can target the wrong host; instead, stop creating a
fallback client and propagate the original error to callers. Replace the
fallback return with a return of nil and the error (after logging it with
context), so callers can decide how to handle connection failures.


func (c *ContainerController) isProtectedContainer(ctx context.Context, containerID string, action string) (*shared_types.Response, bool) {
dockerService, err := c.getDockerService(ctx)
if err != nil {
return nil, false
}
defer dockerService.Close()

details, err := dockerService.GetContainerById(containerID)
if err != nil {
return nil, false
}
name := strings.ToLower(details.Name)
if strings.Contains(name, "nixopus") {
c.logger.Log(logger.Info, fmt.Sprintf("Skipping %s for protected container", action), details.Name)
return &shared_types.Response{
Status: "success",
Message: "Operation skipped for protected container",
Data: map[string]string{"status": "skipped"},
}, true
}
return nil, false
}
12 changes: 10 additions & 2 deletions api/internal/features/container/controller/list_containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ import (
)

func (c *ContainerController) ListContainers(f fuego.ContextNoBody) (*shared_types.Response, error) {
containers, err := c.dockerService.ListAllContainers()
dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
containers, err := dockerService.ListAllContainers()
defer dockerService.Close()
if err != nil {
c.logger.Log(logger.Error, err.Error(), "")
return nil, fuego.HTTPError{
Expand All @@ -21,7 +29,7 @@ func (c *ContainerController) ListContainers(f fuego.ContextNoBody) (*shared_typ

var result []types.Container
for _, container := range containers {
containerInfo, err := c.dockerService.GetContainerById(container.ID)
containerInfo, err := dockerService.GetContainerById(container.ID)
if err != nil {
c.logger.Log(logger.Error, "Error inspecting container", container.ID)
continue
Expand Down
13 changes: 11 additions & 2 deletions api/internal/features/container/controller/list_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ func (c *ContainerController) ListImages(f fuego.ContextWithBody[ListImagesReque
}
}

dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()

filterArgs := filters.NewArgs()
if req.ContainerID != "" {
_, err := c.dockerService.GetContainerById(req.ContainerID)
_, err := dockerService.GetContainerById(req.ContainerID)
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Expand All @@ -45,7 +54,7 @@ func (c *ContainerController) ListImages(f fuego.ContextWithBody[ListImagesReque
filterArgs.Add("reference", pattern)
}

images := c.dockerService.ListAllImages(image.ListOptions{
images := dockerService.ListAllImages(image.ListOptions{
All: req.All,
Filters: filterArgs,
})
Expand Down
12 changes: 11 additions & 1 deletion api/internal/features/container/controller/prune_build_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,17 @@ func (c *ContainerController) PruneBuildCache(f fuego.ContextWithBody[PruneBuild
Status: http.StatusBadRequest,
}
}
err = c.dockerService.PruneBuildCache(types.BuildCachePruneOptions{

dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()

err = dockerService.PruneBuildCache(types.BuildCachePruneOptions{
All: req.All,
})
if err != nil {
Expand Down
11 changes: 10 additions & 1 deletion api/internal/features/container/controller/prune_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ func (c *ContainerController) PruneImages(f fuego.ContextWithBody[PruneImagesReq
filterArgs.Add("dangling", "true")
}

pruneReport, err := c.dockerService.PruneImages(filterArgs)
dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()

pruneReport, err := dockerService.PruneImages(filterArgs)
if err != nil {
c.logger.Log(logger.Error, err.Error(), "")
return nil, fuego.HTTPError{
Expand Down
17 changes: 13 additions & 4 deletions api/internal/features/container/controller/remove_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ import (
func (c *ContainerController) RemoveContainer(f fuego.ContextNoBody) (*shared_types.Response, error) {
containerID := f.PathParam("container_id")

if resp, skipped := c.isProtectedContainer(containerID, "remove"); skipped {
return resp, nil
}
dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()

if resp, skipped := c.isProtectedContainer(c.ctx, containerID, "remove"); skipped {
return resp, nil
}
Comment on lines +24 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use request context for protection check to keep server scoping correct.

Using c.ctx may bypass per-request server/tenant context.

-	if resp, skipped := c.isProtectedContainer(c.ctx, containerID, "remove"); skipped {
+	if resp, skipped := c.isProtectedContainer(f.Context(), containerID, "remove"); skipped {
 		return resp, nil
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if resp, skipped := c.isProtectedContainer(c.ctx, containerID, "remove"); skipped {
return resp, nil
}
if resp, skipped := c.isProtectedContainer(f.Context(), containerID, "remove"); skipped {
return resp, nil
}
🤖 Prompt for AI Agents
In api/internal/features/container/controller/remove_container.go around lines
24 to 26, the protection check is using the controller's global c.ctx which can
bypass per-request server/tenant scoping; change the call to use the incoming
request context (e.g., the local ctx variable or req.Context()) when calling
c.isProtectedContainer so the check runs with the per-request context; ensure
the variable you pass is the request-scoped context in scope at this location.


err := c.dockerService.RemoveContainer(containerID, container.RemoveOptions{Force: true})
err = dockerService.RemoveContainer(containerID, container.RemoveOptions{Force: true})
if err != nil {
c.logger.Log(logger.Error, err.Error(), "")
return nil, fuego.HTTPError{
Expand Down
11 changes: 10 additions & 1 deletion api/internal/features/container/controller/restart_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ import (
func (c *ContainerController) RestartContainer(f fuego.ContextNoBody) (*shared_types.Response, error) {
containerID := f.PathParam("container_id")

err := c.dockerService.RestartContainer(containerID, container.StopOptions{})
dockerService, err := c.getDockerService(f.Context())
if err != nil {
return nil, fuego.HTTPError{
Err: err,
Status: http.StatusInternalServerError,
}
}
defer dockerService.Close()

err = dockerService.RestartContainer(containerID, container.StopOptions{})
if err != nil {
c.logger.Log(logger.Error, err.Error(), "")
return nil, fuego.HTTPError{
Expand Down
Loading
Loading