Skip to content
Merged
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 .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Community Contribution License
## Contribution Licensing (no CLA, inbound=outbound, DCO required)
This project does not use a CLA; contributions are accepted inbound=outbound.
All community contributions in this pull request are licensed under the
[GNU AGPL v3.0 or later](https://www.gnu.org/licenses/agpl-3.0.html), the
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/dco.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ jobs:
# Every non-merge commit in the pull request must carry a Signed-off-by
# trailer matching the commit author's email, certifying the Developer
# Certificate of Origin 1.1 (https://developercertificate.org/).
# Bot-authored commits (dependabot etc.) are exempt.
# Only commits authored from a GitHub-issued bot address are exempt; a
# display name is attacker-controlled and must never grant the exemption.
- name: Check Signed-off-by trailers
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
Expand All @@ -31,8 +32,8 @@ jobs:
while read -r sha; do
author_name="$(git log -1 --format='%an' "${sha}")"
author_email="$(git log -1 --format='%ae' "${sha}")"
case "${author_name}" in
*"[bot]"*) continue ;;
case "${author_email}" in
*"[bot]@users.noreply.github.com") continue ;;
esac
if ! git log -1 --format='%(trailers:key=Signed-off-by,valueonly)' "${sha}" |
grep -qiF "<${author_email}>"; then
Expand Down
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,10 @@ this fork does not try to.

* **Squash merges** must keep the `Signed-off-by:` trailers in the resulting
commit message.

* **Authorship and tooling.** The human contributor is the author of the
commit and the sole signatory of its DCO sign-off. Attribution trailers for
assistive tooling (for example `Co-Authored-By:` naming an AI assistant) are
informational only: they record which tools were used, and do not create
authorship, co-authorship, or any copyright claim. Whoever signs off remains
responsible for the content of the commit, whatever produced it.
8 changes: 8 additions & 0 deletions buildscripts/check-branding.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ if ! grep -q 'func subnetServicesEnabled() bool { return false }' cmd/subnet-uti
err "subnetServicesEnabled() is no longer hard-disabled"
fi

# 6. No vendor encryption key may ship in the binary. Diagnostic output has to
# stay decryptable by the operator who produced it, so encryption must use
# an operator-supplied key or a server-generated one - never a key whose
# private half belongs to a third party.
if git grep -nE 'MII[A-Za-z0-9+/]{64,}' -- 'cmd/*.go' ':!cmd/*_test.go'; then
err "embedded public key found in cmd/; diagnostics must not encrypt to a vendor key"
fi

if [ "${fail}" -ne 0 ]; then
echo "check-branding: FAILED - review docs/rebranding policy before changing brand surfaces" >&2
exit 1
Expand Down
2 changes: 1 addition & 1 deletion cmd/admin-user-add.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ EXAMPLES:
{{.EnableHistory}}

4. Add a new user 'foobar' to Silo/MinIO server, then attach IAM policy "writeonly".
{{.Prompt}} {{.HelpName}} mysilo foobar foo12345
{{.Prompt}} {{.HelpName}} mysilo foobar foo12345
{{.Prompt}} mc admin policy attach mysilo writeonly --user foobar
`,
}
Expand Down
12 changes: 12 additions & 0 deletions cmd/build-constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package cmd

import "strconv"

var (
// Version - version time.RFC3339.
Version = "DEVELOPMENT.GOGET"
Expand All @@ -29,3 +31,13 @@ var (
// CopyrightYear - dynamic value of the copyright end year
CopyrightYear = "0000"
)

// copyrightEndYear returns the end year shown in copyright notices. Release
// builds inject CopyrightYear through ldflags; source builds keep the "0000"
// placeholder, for which the current year is used instead.
func copyrightEndYear() string {
if CopyrightYear == "" || CopyrightYear == "0000" {
return strconv.Itoa(UTCNow().Year())
}
return CopyrightYear
}
4 changes: 2 additions & 2 deletions cmd/idp-ldap-accesskey-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ EXAMPLES:
{{.Prompt}} {{.HelpName}} mysilo/ --temp-only

4. Get list of access keys associated with user 'bobfisher'
{{.Prompt}} {{.HelpName}} mysilo/ uid=bobfisher,dc=example,dc=com
{{.Prompt}} {{.HelpName}} mysilo/ uid=bobfisher,dc=example,dc=com

5. Get list of access keys associated with user 'bobfisher' (alt)
{{.Prompt}} {{.HelpName}} mysilo/ bobfisher

6. Get list of access keys associated with users 'bobfisher' and 'cody3'
{{.Prompt}} {{.HelpName}} mysilo/ uid=bobfisher,dc=example,dc=com uid=cody3,dc=example,dc=com
{{.Prompt}} {{.HelpName}} mysilo/ uid=bobfisher,dc=example,dc=com uid=cody3,dc=example,dc=com

7. Get authenticated user and associated access keys in local server (if not admin)
{{.Prompt}} {{.HelpName}} local/
Expand Down
2 changes: 1 addition & 1 deletion cmd/idp-openid-accesskey-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ EXAMPLES:
{{.Prompt}} {{.HelpName}} mysilo/ --temp-only

4. Get list of access keys associated with internal name 'openidinternalname'
{{.Prompt}} {{.HelpName}} mysilo/ openidinternalname
{{.Prompt}} {{.HelpName}} mysilo/ openidinternalname

5. Get list of access keys associated with ID claim 'openidsub' (default claim is sub)
{{.Prompt}} {{.HelpName}} mysilo/ openidsub
Expand Down
7 changes: 4 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ var mcFlags = []cli.Flag{
},
}

// Help template for mc
// Help template for mc. Built at init time so the copyright end year can fall
// back to the current year in source builds, where ldflags inject nothing.
var mcHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}

Expand All @@ -72,7 +73,7 @@ TIP:

COPYRIGHT:
Copyright (c) 2015-2025 MinIO, Inc.
Copyright (c) 2025-` + CopyrightYear + ` PGSTY
Copyright (c) 2025-` + copyrightEndYear() + ` PGSTY

LICENSE:
GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
Expand Down Expand Up @@ -446,7 +447,7 @@ func printMCVersion(c *cli.Context) {
fmt.Fprintf(c.App.Writer, "Silo object storage client, based on MinIO technology\n")
fmt.Fprintf(c.App.Writer, "Runtime: %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
fmt.Fprintf(c.App.Writer, "Copyright (c) 2015-2025 MinIO, Inc.\n")
fmt.Fprintf(c.App.Writer, "Copyright (c) 2025-%s PGSTY\n", CopyrightYear)
fmt.Fprintf(c.App.Writer, "Copyright (c) 2025-%s PGSTY\n", copyrightEndYear())
fmt.Fprintf(c.App.Writer, "License GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>\n")
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/mirror-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ EXAMPLES:
{{.Prompt}} {{.HelpName}} --older-than 30d s3/test ~/test

13. Mirror server encrypted objects from Amazon S3 cloud storage to a bucket on Amazon S3 cloud storage
{{.Prompt}} {{.HelpName}} --enc-c "mysilo/archive=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA" --enc-c "s3/archive=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5BBB" s3/archive/ mysilo/archive/
{{.Prompt}} {{.HelpName}} --enc-c "mysilo/archive=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA" --enc-c "s3/archive=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5BBB" s3/archive/ mysilo/archive/

14. Update 'Cache-Control' header on all existing objects recursively.
{{.Prompt}} {{.HelpName}} --attr "Cache-Control=max-age=90000,min-fresh=9000" mysilo/video-files mysilo/video-files
Expand Down
2 changes: 1 addition & 1 deletion cmd/put-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ EXAMPLES:
{{.Prompt}} {{.HelpName}} path-to/object mysilo/mybucket/object-prefix/

4. Put an object to Silo/MinIO storage using sse-c encryption
{{.Prompt}} {{.HelpName}} --enc-c "mysilo/mybucket/object=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA" path-to/object mysilo/mybucket/object
{{.Prompt}} {{.HelpName}} --enc-c "mysilo/mybucket/object=MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDA" path-to/object mysilo/mybucket/object

5. Put an object to Silo/MinIO storage using sse-kms encryption
{{.Prompt}} {{.HelpName}} --enc-kms path-to/object mysilo/mybucket/object
Expand Down
15 changes: 15 additions & 0 deletions cmd/subnet-disabled_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package cmd

import (
"io"
"strings"
"testing"
)
Expand Down Expand Up @@ -67,6 +68,20 @@ func TestFreshConfigHasNoThirdPartyDemoAlias(t *testing.T) {
}
}

func TestEncryptedUploadRequiresAnExplicitKey(t *testing.T) {
// Encryption must never fall back to a vendor key: data the operator
// cannot decrypt is not a local artifact. With no PubKey configured the
// encrypted path has no recipient and must fail closed.
up := &SubnetFileUploader{AutoEncrypt: true, FilePath: "testdata/undelivered.txt"}
req, e := up.subnetUploadReq()
if e != nil {
t.Fatalf("subnetUploadReq() = %v, want a request whose body fails closed", e)
}
if _, e = io.ReadAll(req.Body); e == nil {
t.Fatal("encrypted upload body succeeded without a public key; it must fail closed")
}
}

func TestAGPLMessageHasNoCommercialPitch(t *testing.T) {
msg := getAGPLMessage()
for _, needle := range []string{"min.io", "commercial", "subscription"} {
Expand Down
10 changes: 5 additions & 5 deletions cmd/subnet-file-uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ package cmd
import (
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"io"
"mime/multipart"
"net/http"
Expand Down Expand Up @@ -133,10 +133,10 @@ func (i *SubnetFileUploader) subnetUploadReq() (*http.Request, error) {
errfn = sw.AddError
key := i.PubKey
if key == nil {
key, e = base64.StdEncoding.DecodeString(defaultPublicKey)
if e != nil {
return
}
// This build ships no vendor encryption key: without an
// explicit public key there is no recipient to encrypt to.
e = errors.New("no public encryption key configured")
return
}
pk, e := bytesToPublicKey(key)
if e != nil {
Expand Down
14 changes: 4 additions & 10 deletions cmd/support-inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package cmd

import (
"context"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
Expand All @@ -42,10 +41,6 @@ import (
"github.com/minio/pkg/v3/console"
)

const (
defaultPublicKey = "MIIBCgKCAQEAs/128UFS9A8YSJY1XqYKt06dLVQQCGDee69T+0Tip/1jGAB4z0/3QMpH0MiS8Wjs4BRWV51qvkfAHzwwdU7y6jxU05ctb/H/WzRj3FYdhhHKdzear9TLJftlTs+xwj2XaADjbLXCV1jGLS889A7f7z5DgABlVZMQd9BjVAR8ED3xRJ2/ZCNuQVJ+A8r7TYPGMY3wWvhhPgPk3Lx4WDZxDiDNlFs4GQSaESSsiVTb9vyGe/94CsCTM6Cw9QG6ifHKCa/rFszPYdKCabAfHcS3eTr0GM+TThSsxO7KfuscbmLJkfQev1srfL2Ii2RbnysqIJVWKEwdW05ID8ryPkuTuwIDAQAB"
)

var supportInspectFlags = append(subnetCommonFlags,
cli.BoolFlag{
Name: "legacy",
Expand Down Expand Up @@ -173,11 +168,10 @@ func mainSupportInspect(ctx *cli.Context) error {
}
}

// Fall back to MinIO public key.
if len(publicKey) == 0 {
// Public key for MinIO confidential information.
publicKey, _ = base64.StdEncoding.DecodeString(defaultPublicKey)
}
// Without a user-supplied public key the server generates a random
// key and returns it to the caller, who is the only holder. This
// build never falls back to a vendor key: inspect output must stay
// decryptable by the operator who produced it.
}

key, r, e := client.Inspect(context.Background(), madmin.InspectOptions{
Expand Down
18 changes: 14 additions & 4 deletions cmd/support-proxy-set.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (s supportProxySetMessage) JSON() string {

var supportProxySetCmd = cli.Command{
Name: "set",
Usage: "configure proxy to given URL",
Usage: "configure the SUBNET proxy URL (disabled in this build)",
Action: mainSupportProxySet,
OnUsageError: onUsageError,
Before: setGlobalsFromContext,
Expand All @@ -58,9 +58,14 @@ USAGE:
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. Set the proxy to http://my.proxy for cluster with alias 'mysilo'
{{.Prompt}} {{.HelpName}} mysilo http://my.proxy
DESCRIPTION:
This setting configures the outbound path a server uses to reach MinIO
SUBNET. Since this Silo build disables SUBNET entirely, the command is
retained for CLI compatibility and always exits with an error. Use
'{{.HelpName}} ..' -> 'remove' to clear an existing proxy setting.

EXIT STATUS:
1 - SUBNET services are disabled
`,
}

Expand All @@ -72,6 +77,11 @@ func checkSupportProxySetSyntax(ctx *cli.Context) {

// mainSupportProxySet is the handle for "mc support proxy set" command.
func mainSupportProxySet(ctx *cli.Context) error {
if !subnetServicesEnabled() {
// Setting a proxy configures the server's outbound path to SUBNET.
// Removal stays available so operators can clear a legacy setting.
return subnetDisabledExit()
}
// Check for command syntax
checkSupportProxySetSyntax(ctx)
setSuccessMessageColor()
Expand Down
Loading