HN user

johnlbevan2

429 karma

See https://news.ycombinator.com/user?id=johnlbevan

Posts1
Comments171
View on HN

ps. As for what to do with the findings.

Filter for `HasEverRun=true`; if it's not run, the secrets can't have been exposed.

Review the URL; this says who you're calling. Purists would say that if you've called any endpoints there's a risk. However for most companies I'd say you can trust services provided by folk like Microsoft (they host GitHub anyway) and Snyk (if you're relying on them for security scanning, you should be able to trust them), so if you see webhooks to Azure DevOps (dev.azure.com) or to Snyk (api.snyk.io) you can assume that anything exposed there isn't a concern. You don't need to worry about proxys on egress - since this is GitHub Cloud, so calls egress from GitHub rather than through your own network. So the only concerns would be in house or third party developed endpoints where you feel those companies (/their employees who have access to their ingress logs) may be a risk.

Powershell Script to get all webhooks that have actually run (we can't filter by date; but this may wipe out a significant number):

    # Authenticate via `gh auth login -s admin:enterprise` before running this script
    # Save this script as c:\\temp\GHWebookAudit.ps1; then navigate to c:\\temp\ and invoke via `.\GHWebookAudit.ps1 -Orgs @("MyExampleOrg", "MyOtherExampleOrg") -InformationAction Continue`
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory)]
        [string[]]$Orgs
    )

    $results = foreach ($org in $Orgs) {
        Write-Information "Fetching ALL repositories for org [$org]..."
        
        # gh api --paginate fetches every page and outputs a stream of JSON arrays
        # We use -Raw to ensure we capture the full stream before converting
        $reposJson = gh api --paginate "orgs/$org/repos?per_page=1000"
        
        # ConvertFrom-Json can handle multiple JSON arrays in the stream
        $repos = $reposJson | ConvertFrom-Json

        # Sometimes the pagination returns a single array or a list of arrays; 
        # Ensure we are iterating over the objects themselves.
        $repoList = if ($repos.GetType().IsArray -and $repos[0].GetType().IsArray) { 
            $repos | ForEach-Object { $_ } 
        } else { 
            $repos 
        }

        Write-Information "Found $($repoList.Count) repositories. Starting audit..." 

        foreach ($repoObj in $repoList) {
            $repoName = $repoObj.name
            $fullRepo = "$org/$repoName"
            Write-Information "Checking: $fullRepo"

            # Get all hooks for the repository
            $hooksJson = gh api "repos/$fullRepo/hooks" 2>$null
            if (-not $hooksJson) { continue }
            
            $hooks = $hooksJson | ConvertFrom-Json

            foreach ($hook in $hooks) {
                $hookId = $hook.id
                $hookUrl = $hook.config.url

                # Get the most recent delivery... we could pontentially check for activity between the impacted dates, but that would need additional filters/commplexity; for now keeping it relatively simple
                # correction: this only goes back 3 days; so doesn't work... https://docs.github.com/en/webhooks/testing-and-troubleshooting-webhooks/viewing-webhook-deliveries
                # # $deliveriesJson = gh api "repos/$fullRepo/hooks/$hookId/deliveries" --limit 1 2>$null
                # instead use th eexisting hook response's last response status just to say if it has run; though that doesn't say when

                # Extract last response details
                $lastStatus = $hook.last_response.status
                $lastCode   = $hook.last_response.code
                $hasEverRun = ($lastStatus -eq 'active')  # active vs unused

                [PSCustomObject]@{
                    Organization = $org
                    Repository   = $repoName
                    HookID       = $hookId
                    Active       = $hook.active
                    URL          = $hookUrl
                    HasEverRun   = $hasEverRun
                    LastStatus   = $lastStatus
                    LastHTTPCode = $lastCode
                    UpdatedAt    = $hook.updated_at
                }
            }
        }
    }

    # Final Output
    if ($results.Count) {
        $results | Export-Csv -Path "./Full_Webhook_Audit_Report.csv" -NoTypeInformation
        Write-Information "Audit complete! $($results.Count) hooks found. Results saved to Full_Webhook_Audit_Report.csv"
    } else {
        Write-Information "No webhooks found across the organizations."
    }

Assuming I've understood correctly...

Checking the listed impacted web hooks I noticed that no repo's listed twice, even though some have multiple hooks defined... That makes me think the report may have a bug.

Also, many of the listed hooks show as `This hook has never been triggered`; which if correct means it wouldn't have had an issue as the compromised payload's never been sent to it.

I'll write a powershell script (well, AI will write it and then I'll tweak) to help check which webhooks have been called in this time window (or at least, say they were most recently triggered after the issue first began) to help get a more accurate report of what's concerning. If that proves useful, I'll share here.

Great point... On Sword and Laser (a book club/podcast) the idea of different types of reader is often discussed; i.e. what's the main driver behind liking a book:

  - Plot
  - World Building
  - Character
  - etc (There's a specific list mentioned, but I can't recall it)
That's the simpler classification side of things, so easier to code up... Your example of the canoe trip would be significanlty more complex; but definitely more a scenario worthy of AI over basic heuristics... and something that would need a conversation to drill down into (i.e. did the story evoke the scenery of their trip, or was it reflecting the relationship between the people, etc).

NB: GitHub was purchased by MS 5 years ago. All these events are in the last month.

It's apparant that it wasn't without issues prior to acquisition (e.g. a quick search for GitHub issues prior to 2018 gives this: https://techcrunch.com/2017/07/31/github-goes-down-and-takes...) - reporting issues in 2017, 2015, and 2012.

I don't have the data to comment on whether it was better before or after MS acquisition, but would suggest this isn't the best sample size to base any conclusions on.

It seems several people have encountered the same issues in the past week, after not seeing anything before. Sharing here as likely others are having the issue but haven't gone to the forums / maybe other Android users who aren't on FairPhones are also impacted by the issue.

Error message

  Android Recovery
  Fairphone/FP3/FP3
  11/8901.4.A.0017.3/gms-15368f27
  user/release-keys
  Use volume up/down and power.
  Cannot load Android system.  Your data may be corrupt.  If
  you continue to get this message, you may need to perform
  a factory data reset and erase all user data stored on this
  device.
  Try agian
  Factory data reset
I thought sharing here may aid discovery / if we can collect data from those hitting this issue maybe we can more easily identify the underlying cause.

I'd say "blacklist" and "whitelist" are more offensive / have a stronger argument of colour being used to discriminate (albeit not directly related to races) / would be better to have "deny list" and "allow list".

"Race condition" is just as offensive as "Master Branch" - neither are relating to prejudice / historic injustice; but use different meanings of these potentially loaded words.

That said, nothing against switching to non-loaded terms; especially if the effort to do so is less than the effort to debate it. But we mustn't accuse people of being racist just because they're using terminology that some are offended by when those using the terminology are simply using terminology they've learnt, and could have no reasonable expectation to have considered that it may be deemed offsensive.

Another factor may be subjective vs absolute data points in the source.

"Do you work from home more than 50% of your working hours?" has a simple yes/no answer. "What is your salary, including average annual bonus, after tax?" has a single numeric answer.

"How many years have you been a developer?" sounds simple; but has interpretation issues. Do I count from my first line of code when playing as a kid, my first computer science class, my first paying job as a developer, or some other time? If this is a measure of seniority (e.g. we define senior as anyone who's been coding for 10+ years) there will be a mixed bag.

This may mean that despite trying to factor out variables they're hiding in the noise of bad data; so may still have a hand in the result. i.e. Those developers who've counted 9 years developing from their first salaried job and now earn more and work from home are in the same group as those who've just graduated but counted their time coding from their 8-year-old-self's first foray who are in their first year of the job, and thus on lower salary and less perks.

There seems to be an assumption that the skill of creating fire was discovered once. Knowledge gets lost; and over a 250,000 year period it's pretty likely that even something as important as this may be lost a few times / maybe only to some groups at a time. If you prove that one group of Neanderthals didn't make fire that's not the same as proving that no Neanderthals knew how to create fire.

Related: Some great tips and ways to think about cooking as you would other skills: https://www.goodreads.com/en/book/show/25770528. Examples of some good tips from there...

When using a new ingredient, try it in something you're already familiar with, so you can isolate that ingredient, rather than introducing it in a completely new recipe where you can't easily tell what impact that ingredient has vs others in the recipe.

Think about how to setup your kitchen - is it better to have all your spice containers in a group with one another, where they all look similar, or to put them alongside the items you use them with (tumeric with your basmati rice, nutmeg with your pestle & mortar, etc) so that it's easier to find everything you need for a recipe.

Learn how to ask a question.

Think of all the times you've seen poorly worded questions on Stack Overflow, in support tickets, etc. Think of the power that being able to get answers to your questions has.

Most of us are good at asking questions where we're working within our comfort zones, but struggle when we're on unfamiliar territory (e.g. I'll ask a better question if I have some issue with my code than I would if I were talking to a mechanic about a problem with my car, since I don't know the terminology / worry more about appearing ignorant in the latter scenario). However, by taking time to consider what's useful to the mechanic & what I can report as fact vs my opinion, I can ask a cleaner question.

Related, it's also good to learn how to think about things as a collection of dependencies, and how to debug/analyse issues by testing different parts of that dependency graph to isolate variables and narrow down where in that graph an issue must exist. This both helps to ask cleaner questions, provide more background information, and often to resolve issues for yourself.

It will be interesting to read your post in a few months time, when you hit the issues caused by using a monolith which could be resolved by splitting that service apart.

Introducing components to match on various forms of value seems odd. Ideally standardise on those names; but if that's not possible (and you're using microservices), why not have a service to correct the name, rather than a library deployed to every endpoint? Then you call that service with data containing `first_name` or `givenname` and it returns that message with the standardised form. Or have a "global key" service; where you send the source system name and value, and have that translated for the destination via a lookup, allowing any field names or defined values to be translated by a generic reusable component:

  Entity    | System Name | System Value | GlobalKey
  -------------------------------------------------------------------------------------------
  Boolean   | HR          | TRUE         | 52582622-4322-445b-bb7a-8ca118d0ca2b
  Boolean   | HR          | FALSE        | 688c2298-6b99-4c31-a356-1ab9b1caacde
  Boolean   | Finance     | 1            | 52582622-4322-445b-bb7a-8ca118d0ca2b
  Boolean   | Finance     | 0            | 688c2298-6b99-4c31-a356-1ab9b1caacde
  Boolean   | Sales       | Yes          | 52582622-4322-445b-bb7a-8ca118d0ca2b
  Boolean   | Sales       | No           | 688c2298-6b99-4c31-a356-1ab9b1caacde
  FieldName | HR          | GivenName    | 3de31cff-e4bb-4d4a-a819-fd96c7c5032e
  FieldName | HR          | Surname      | e799b891-1eeb-4598-85a5-a9534d3a3a4c
  FieldName | Finance     | First_Name   | 3de31cff-e4bb-4d4a-a819-fd96c7c5032e
  FieldName | Finance     | Last_Name    | e799b891-1eeb-4598-85a5-a9534d3a3a4c
  FieldName | Sales       | FirstName    | 3de31cff-e4bb-4d4a-a819-fd96c7c5032e
  FieldName | Sales       | Surname      | e799b891-1eeb-4598-85a5-a9534d3a3a4c
As for "handcrafted XML"... the alternative looks like handcrafted code... For translation a language like XSLT which was designed for translating data from one format to another seems like a good choice. You can also use this to get around your translation issue by defining a central "universal" format; so you can have XSLTs to translate messages from source systems to the universal format, then other XSLTs to translate from universal to the destination; so that adding or removing a system (/service) only impacts that system / you don't need to rewrite every point-to-point interaction of that service with another (OK, not point to point since we have microservices; but if they're not adding value by abstracting you away from point to point then essentially you've just got complex point-to-point interactions rather than simple point-to-point).

I agree that SO is a great place in my experience.

The worst area seems to be JavaScript, since that world is full of trendy new options. The most common one I see here is where someone wants a solution to a JavaScript problem and gets a JQuery response; even though a JavaScript solution would be trivial and the OP's not mentioned JQuery. That has a tendency to push people into using libraries where they're not required.

For .Net questions most of the issues seem to be in the ORM space; i.e. the boundary between .Net and SQL; where people asking for help with SQL are pointed to LINQ, and people wanting to do database-first are pushed towards code-first solutions.

It's not really an SO problem (or at least not a problem that I can think of an easy way they'd be able to solve); more there are so many solutions and no best way; and giving the full context of the developer's experience, preferences, and situation would take several essays, then matching that to those qualified to supply a suitable answer for that particular scenario would require really intelligent filtering; assuming that such people exist and are active on SO. So the current solution of having lots of answers to pick from, and allowing people to up-vote and comment to help remove bad answers and help show which answers are the more generally preferred (thus driving those who don't have a preference to follow the general consensus and thus move towards some form of standard approach within the community) seems a pretty good one.

I think a lot of us technical minded people fall into the same trap; we start with the technology, trying to solve problems of making a site dynamic and secure before considering the content. With the exception of sites solely aimed at demonstrating new technologies, the purpose of a site is to provide content (OK, sometimes to provide functionality too; but that's content in a sense). The key is to work out what content needs to be on the site & start with that. Once you've got that down you can consider how it can be improved; and that's where these other pieces start coming in. But start by defining the problem to be addressed, then look for the tool to fix that problem; don't go off and find something trendy then work out how you can make problems that it can handle, or how you can force your problem into being the kind of problem which that tool could fix; move on and find the tool that makes sense.

This is all obvious at the start of the project, but the moment you see a rabbit hole it's very hard to resist going down it. For that, keep a list of what's important nearby, and each time you get back from a break check that list and ensure you're obeying it. That list will start with a bunch of don'ts; to keep you away from bad habits, followed by your priority task list of what you need to create your MVP / the MUSTS of your solution. Once you have a working solution and have ticked off all the musts from your list, you can then play safe in the knowledge that you've got a checked in working version; and the remaining time is just experimenting / tweaking / playing.

Anyway, that's the theory... I've not managed to stick to it yet; let me know if it works for you though ;).

Fully agreed that in simple use cases simple solutions make sense; I've been arguing similarly for the NoSQL movement for years (i.e. NoSQL being great for large scale systems; but for most companies day-to-day needs SQL wins out).

However, it would be good to have a bit more in the article to say what AI/ML* is in this context, and a couple of scenarios where it beats SQL; i.e. otherwise it just sounds like the rantings of an old man "in my day we only had turnips; you needed a snack: turnip; you needed a pillow: turnip". By showing a few good use cases allows you to better contrast the product / get an understanding of where the boundaries are between the technologies.

*NB: When I first read this I assumed the author was talking about AIML (artificial intelligence markup language) rather than AI/ML (artificial intelligence / machine language)... as though the slash was included, there was no use of the full terms.