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
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.24-alpine AS builder
FROM golang:1.25-alpine AS builder

WORKDIR /app

Expand All @@ -11,10 +11,17 @@ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app ./cmd/grpc/ma

FROM alpine:latest

WORKDIR /root/
# Create an unprivileged user and group
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /home/appuser

COPY --from=builder /app/app .
COPY --from=builder /app/config/ /etc/app/

# Change ownership of files to appuser
RUN chown -R appuser:appgroup /home/appuser /etc/app

USER appuser
ENTRYPOINT ["./app"]
CMD ["--config /etc/app/local.yaml"]
14 changes: 11 additions & 3 deletions cmd/grpc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import (
"github.com/bmstu-itstech/scriptum-back/internal/config"
"github.com/bmstu-itstech/scriptum-back/internal/infra/docker"
"github.com/bmstu-itstech/scriptum-back/internal/infra/local"
"github.com/bmstu-itstech/scriptum-back/internal/infra/mock"
"github.com/bmstu-itstech/scriptum-back/internal/infra/postgres"
"github.com/bmstu-itstech/scriptum-back/internal/infra/sso"
"github.com/bmstu-itstech/scriptum-back/internal/infra/watermill"
"github.com/bmstu-itstech/scriptum-back/pkg/logs"
"github.com/bmstu-itstech/scriptum-back/pkg/server"
Expand All @@ -38,7 +38,15 @@ func main() {
repos := postgres.MustNewRepository(cfg.Postgres, l)
runner := docker.MustNewRunner(cfg.Docker, l)
storage := local.MustNewStorage(cfg.Storage, l)
mockIAP := mock.NewIsAdminProvider()

ssoApi, closeFn := sso.MustNewSSOClient(cfg.SSO, l)

defer func() {
err := closeFn()
if err != nil {
l.Error("failed to close SSO client", slog.String("error", err.Error()))
}
}()

jPub, jSub := watermill.NewJobPubSubGoChannels(l)

Expand All @@ -47,7 +55,7 @@ func main() {
BoxRepo: repos,
FileReader: storage,
FileUploader: storage,
IsAdminProvider: mockIAP,
IsAdminProvider: ssoApi,
JobProvider: repos,
JobPublisher: jPub,
JobRepository: repos,
Expand Down
5 changes: 5 additions & 0 deletions config/local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ logging:

storage:
base_path: "uploads"

sso:
host: "localhost"
port: "44044"
app_id: 1
4 changes: 2 additions & 2 deletions easyp.lock
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/googleapis/googleapis common-protos-1_3_1 h1:s8d5N7+VjksySahU4JpUGSju5SqkmQNtweRfsin9SyM=
github.com/grpc-ecosystem/grpc-gateway v0.0.0-20251127211339-d2d5e587243b4254ac96b76ce19636e0fd734a5e h1:qihtPAOYuB5MmdtIx/0GX3DZrVBCp/kZz2iolgsuOys=
github.com/googleapis/googleapis common-protos-1_3_1 h1:TsE+JW4H/zsB0phfwMO1DragQ4oaGfoVuGHV5aGfn2I=
github.com/grpc-ecosystem/grpc-gateway v0.0.0-20251127211339-d2d5e587243b4254ac96b76ce19636e0fd734a5e h1:48F3p4F2740v+ZV/mCXiBwQcK+LBbN8h+alOaIx9BD0=
44 changes: 28 additions & 16 deletions easyp.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
version: v1alpha
lint:
use:
- DEFAULT
use:
- DEFAULT
deps:
- github.com/googleapis/googleapis@common-protos-1_3_1
- github.com/grpc-ecosystem/grpc-gateway
- github.com/googleapis/googleapis@common-protos-1_3_1
- github.com/grpc-ecosystem/grpc-gateway@v2.19.1
generate:
inputs:
- directory: "api/v2"
plugins:
- name: go
out: gen/go
opt:
paths: source_relative
- name: go-grpc
out: gen/go
opt:
paths: source_relative
inputs:
- directory: "api/v2"
plugins:
- name: go
out: gen/go
opt:
paths: source_relative
module: "github.com/bmstu-itstech/scriptum-back"
with_imports: true

- name: go-grpc
out: gen/go
opt:
paths: source_relative

- name: grpc-gateway
out: gen/go
opts:
paths: source_relative

- name: openapiv2
out: ./gen/openapi
opts:
simple_operation_ids: true
15 changes: 7 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
module github.com/bmstu-itstech/scriptum-back

go 1.24.0

toolchain go1.24.3
go 1.25.0

require (
github.com/BOBAvov/protos_sso v0.0.17
github.com/ThreeDotsLabs/watermill v1.5.1
github.com/fatih/color v1.18.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3
Expand All @@ -15,7 +14,7 @@ require (
github.com/stretchr/testify v1.11.1
github.com/zhikh23/pgutils v1.1.3
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846
google.golang.org/grpc v1.74.2
google.golang.org/grpc v1.76.0
google.golang.org/protobuf v1.36.10
)

Expand Down Expand Up @@ -52,11 +51,11 @@ require (
github.com/subosito/gotenv v1.6.0 // 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
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
32 changes: 18 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BOBAvov/protos_sso v0.0.17 h1:Dvhz4WnB8LNOKA5VE5RCCKWVqML1bdj6/Ck1f2vPKeU=
github.com/BOBAvov/protos_sso v0.0.17/go.mod h1:+bhsk/b46aqFYW3w8q01IxAiL914SpU5UicLhg/Nrx0=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ThreeDotsLabs/watermill v1.5.1 h1:t5xMivyf9tpmU3iozPqyrCZXHvoV1XQDfihas4sV0fY=
Expand Down Expand Up @@ -101,30 +103,32 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
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=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
7 changes: 7 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Config struct {
Logging Logging `mapstructure:"logging"`
Postgres Postgres `mapstructure:"postgres"`
Storage Storage `mapstructure:"storage"`
SSO SSO `mapstructure:"sso"`
}

type Docker struct {
Expand All @@ -37,6 +38,12 @@ type Storage struct {
BasePath string `mapstructure:"base_path"`
}

type SSO struct {
Host string `mapstructure:"host"`
Port string `mapstructure:"port"`
AppID int32 `mapstructure:"app_id"`
}

func Load(path string) (*Config, error) {
// Нетривиальный момент Viper, не описанный в документации, но описанный в
// https://github.com/spf13/viper/issues/1797
Expand Down
21 changes: 0 additions & 21 deletions internal/infra/mock/is_admin_provider.go

This file was deleted.

75 changes: 75 additions & 0 deletions internal/infra/sso/is_admin_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package sso

import (
"context"
ssov1 "github.com/BOBAvov/protos_sso/gen/go/sso"
"github.com/bmstu-itstech/scriptum-back/internal/config"
"github.com/bmstu-itstech/scriptum-back/internal/domain/value"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
"log/slog"
"net"
"strconv"
)

type SSO struct {
conn *grpc.ClientConn
api ssov1.AuthClient
l *slog.Logger
AppID int32
}

func MustNewSSOClient(config config.SSO, l *slog.Logger) (*SSO, func() error) {
sso, closeFn, err := NewSSOClient(config, l)
if err != nil {
panic("Error creating SSO client: " + err.Error())
}
return sso, closeFn
}

func NewSSOClient(config config.SSO, l *slog.Logger) (*SSO, func() error, error) {
addr := net.JoinHostPort(config.Host, config.Port)
cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, func() error { return nil }, err
}

closeFn := cc.Close

return &SSO{
api: ssov1.NewAuthClient(cc),
conn: cc,
l: l,
AppID: config.AppID,
}, closeFn, nil
}

// IsAdmin checks if the user with the given uid has admin privileges.
// Note: uid parameter is of type value.UserID but is converted to int64 for the gRPC call.
func (s *SSO) IsAdmin(ctx context.Context, uid value.UserID) (bool, error) {
const op = "infra.SSO.IsAdmin"

l := s.l.With(
slog.String("op", op),
slog.Int64("uid", int64(uid)),
)

l.Debug("Checking admin status")
// Add metadata with application ID to the context
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(
"x-user-id", strconv.FormatInt(int64(s.AppID), 10),
))
// Call the IsAdmin method on the SSO server
resp, err := s.api.IsAdmin(ctx, &ssov1.IsAdminRequest{
UserId: int64(uid),
})
if err != nil {
l.Error("Failed to check admin status", slog.String("error", err.Error()))
return false, err
}

l.Debug("Admin status", slog.Bool("is_admin", resp.IsAdmin))

return resp.IsAdmin, nil
}
18 changes: 15 additions & 3 deletions tests/suite/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package suite

import (
"context"
"fmt"
"math/rand/v2"
"net"
"os"
Expand All @@ -20,8 +21,8 @@ import (
"github.com/bmstu-itstech/scriptum-back/internal/config"
"github.com/bmstu-itstech/scriptum-back/internal/infra/docker"
"github.com/bmstu-itstech/scriptum-back/internal/infra/local"
"github.com/bmstu-itstech/scriptum-back/internal/infra/mock"
"github.com/bmstu-itstech/scriptum-back/internal/infra/postgres"
"github.com/bmstu-itstech/scriptum-back/internal/infra/sso"
"github.com/bmstu-itstech/scriptum-back/internal/infra/watermill"
"github.com/bmstu-itstech/scriptum-back/pkg/logs"
"github.com/bmstu-itstech/scriptum-back/pkg/server/auth"
Expand Down Expand Up @@ -49,6 +50,11 @@ func suiteConfig() config.Config {
Storage: config.Storage{
BasePath: "../uploads",
},
SSO: config.SSO{
Host: os.Getenv("SSO_HOST"),
Port: os.Getenv("SSO_PORT"),
AppID: 1,
},
}
}

Expand All @@ -59,7 +65,13 @@ func New(t *testing.T) (context.Context, *Suite) {
repos := postgres.MustNewRepository(cfg.Postgres, l)
runner := docker.MustNewRunner(cfg.Docker, l)
storage := local.MustNewStorage(cfg.Storage, l)
mockIAP := mock.NewIsAdminProvider()
ssoApi, closeFn := sso.MustNewSSOClient(cfg.SSO, l)
t.Cleanup(func() {
err := closeFn()
if err != nil {
l.Error(fmt.Sprintf("failed to close sso client: %s", err.Error()))
}
})

jPub, jSub := watermill.NewJobPubSubGoChannels(l)

Expand All @@ -68,7 +80,7 @@ func New(t *testing.T) (context.Context, *Suite) {
BoxRepo: repos,
FileReader: storage,
FileUploader: storage,
IsAdminProvider: mockIAP,
IsAdminProvider: ssoApi,
JobProvider: repos,
JobPublisher: jPub,
JobRepository: repos,
Expand Down