Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

ADD FUNC TO CHANGE VISIBILTY FOR GH PACKAGES

Open
#129 0 comments 0 reactions 1 assignee View on GitHub

Maintainers usually reply within 1 day

@patrick-hermann-sva is already working on this.

Since Oct 27, 2025.

Assessment

This issue has not been assessed yet.

Description

epic:dagger-modules
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

// GitHub API base URL
const baseURL = "https://api.github.com"

func ghRequest(url, token string) (map[string]interface{}, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("Authorization", "Bearer "+token)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err == io.EOF {
		return nil, nil
	} else if err != nil {
		return nil, err
	}
	return result, nil
}

func ghRequestList(url, token string) ([]map[string]interface{}, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("Authorization", "Bearer "+token)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
	}

	var result []map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}
	return result, nil
}

func findInList(list []map[string]interface{}, name string) map[string]interface{} {
	for _, pkg := range list {
		if pkg["name"] == name {
			return pkg
		}
	}
	return nil
}

// 🔒 Function to change a package's visibility
func setPackageVisibility(org, pkgName, visibility, token string) error {
	url := fmt.Sprintf("%s/orgs/%s/packages/container/%s/visibility", baseURL, org, pkgName)

	body := map[string]string{"visibility": visibility}
	jsonBody, _ := json.Marshal(body)

	req, err := http.NewRequest("PATCH", url, bytes.NewReader(jsonBody))
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+token)
	req.Header.Set("Accept", "application/vnd.github+json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	responseBody, _ := io.ReadAll(resp.Body)

	if resp.StatusCode >= 400 {
		return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(responseBody))
	}

	fmt.Printf("✅ Updated visibility to %s (HTTP %d)\n", visibility, resp.StatusCode)
	return nil
}

func main() {
	org := "stuttgart-things"
	pkgName := "flux-source"
	token := os.Getenv("GITHUB_TOKEN")
	if token == "" {
		log.Fatal("❌ Missing GITHUB_TOKEN in environment")
	}

	listURL := fmt.Sprintf("%s/orgs/%s/packages?package_type=container", baseURL, org)
	fmt.Printf("🔎 Listing from: %s\n", listURL)
	list, err := ghRequestList(listURL, token)
	if err != nil {
		log.Printf("⚠️ Error listing packages: %v\n", err)
	}

	found := findInList(list, pkgName)
	if found != nil {
		fmt.Printf("✅ Found %s (visibility: %s)\n", found["name"], found["visibility"])
		return
	}

	directURL := fmt.Sprintf("%s/orgs/%s/packages/container/%s", baseURL, org, pkgName)
	fmt.Printf("🔍 Not found in list, trying direct lookup: %s\n", directURL)
	direct, err := ghRequest(directURL, token)
	if err != nil {
		log.Fatalf("❌ Package not found: %v", err)
	}

	name := direct["name"]
	visibility := direct["visibility"]
	versionCount := direct["version_count"]

	fmt.Printf("✅ Found package: %s\n", name)
	fmt.Printf("   → Visibility: %s\n", visibility)
	fmt.Printf("   → Versions: %.0f\n", versionCount)

	// 🔄 Example: change visibility to public
	newVisibility := "public" // or "private"
	if visibility != newVisibility {
		fmt.Printf("⚙️ Changing visibility from %s → %s...\n", visibility, newVisibility)
		if err := setPackageVisibility(org, pkgName, newVisibility, token); err != nil {
			log.Fatalf("❌ Failed to update visibility: %v", err)
		}
	} else {
		fmt.Println("ℹ️ Package already has desired visibility.")
	}
}

This is not a bug in your Go code. It’s a GitHub REST API limitation for org-owned GHCR packages:

For organization-owned container packages (flux-source under stuttgart-things), the API does not allow changing visibility at all.

That’s why the PATCH endpoint returns 404 Not Found, even though the package exists and your token is valid.

Only user-owned packages can currently have their visibility changed via API.

Dominant language
Go
Stars
3
Forks
0
Avg merge
21h 53m
Merged PRs (30d)
26

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from stuttgart-things/dagger

All issues in stuttgart-things/dagger

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.