Wondering about a practice that a contractor did

5/10/2025

I have a question I want to pose to those of you who are freelance software developers, or have done that in the past. It concerns the way a contractor who works for us, has conducted himself. I’ll explain below.

Currently I work in state government as a senior software engineer, for one of the largest state departments in my state. I’ve been in my position for 10 years. About 7 years ago the task of administering our on-prem TFS was added to me, as the former TFS Admin was leaving. Since then another software engineer was also assigned the TFS Administrator role. Two years ago we were instructed to migrate all our source code from TFS to GitHub in GitHub.com. We are now our state department’s GitHub administrators, too. The code in our TFS is from longer ago than 10 years, as developers moved copies of their code from several years ago, into TFS. Some of this code goes back 15+ years. And because there are so many developers involved over the years, there are hundreds, perhaps thousands of Visual Studio solutions in our TFS, which we’ve migrated to GitHub. It is hard to tell because of the different ways TFS handles what is called TFS Projects (now Azure DevOps (ADO) Projects) vs. what GitHub Projects are like, which is nothing like what TFS/ADO Projects are like. The migration of our code base from our on-prem TFS to a GitHub Organization in GitHub.com took us 9 months, because our employer wouldn’t allow us to use GitHub Import, so we had to do it all by hand. When we migrated our code to our organization in GitHub, we gave all the repositories a visibility status of Internal. A visibility of Internal is available in GitHub Organizations and is between Private and Public. It does allow everyone who is a member of the Organization to see all the code of all those repos, but not modify any of the code unless they are a member of that repo.

Early last year a new contractor was hired, named Richard (not his real name). He was hired just a few weeks after we finished migrating the code out of TFS into GitHub. We added him to the GitHub organization. He then went about looking at various repos. He then complained to everyone about the habit all developers over several years had of leaving important secrets, such as database connection strings, in the source code. This upset everyone because Richard was judging a lot of people’s coding styles when that code had all been written and saved to TFS that was on-prem. i.e: everyone felt like it was safe because it was in-house and when most of it was written the concept of not saving secrets in source code was not considered a bad practice. It was clear to all developers that Richard was just trying to make himself look competent and all the rest of us incompetent, rather than considering the conditions under which that old code had been written. Upper management isn’t aware of these considerations, so Richard looked brilliant, whereas the rest of us didn’t. Most of the code is so old that it is no longer in production, but management wanted it to be migrated for historical reasons. All the new code’s secrets are not kept in the code, but that wasn’t mentioned in Richard’s accusation.

This behavior by Richard at the beginning of his employment with us should have been a warning to me that he isn’t someone I can put full trust in, but I didn’t take heed. This has recently become apparent to me, but even now I’m not sure if it is wrong or only customary practice done by contractors. When the other GitHub Admin and I configured our GitHub organization we developed some rules that we intended to have everyone adhere to. One of these is the default branch would be named main. Another was that on those projects where more than one developer is involved, then no one could create a pull request (PR) to merge their changes back into the default branch, and approve their PR. (We make exceptions for a single contributor to a repo, as we have a lot of projects like that, due to how small the project is, only one developer is needed for the project/repo.) A year ago, when Richard started contributing, he asked that the default branch on the repos he was working in be named master. At the time I thought I would make the exception to our rule, because I know some people who’ve developed software for many years and saved their code changes in Git, are used to the original default branch name of master. So, I created a master branch from main in the two repos Richard was working in, then changed the default branch’s name from main to master. Also, Richard said that having to wait for someone else on the team to approve his PRs was too burdensome, since he lives two time zones east of us and, he claimed, he works late at night and wants to commit and approve his PRs, rather than wait. At the time I thought that a valid argument, so I lifted that restriction as well.

Now I regret having made those two exceptions. One of the repos Richard is no longer working with, so he’s handed that over to another developer, a coworker and regular employee, who has taken it over. This other developer’s name is Charles (not his real name). Charles is used to the default branch being named main, so he asked me to reconfigure the repo with main as the default branch name and move all the code Richard had written from master back into main. This seems like an easy enough request, so I tried doing it. I’ve spent two days at it, because I discovered that I couldn’t merge master back into main, as they no longer have a common commit Git history. This really surprised me, but doing a git log at the command line provided that master’s history had nothing in common with main’s history. I know there are multiple ways of having two branches in the same repo not have a common Git history, but there’s no way I can detemine how Richard overwrote master’s history since all such actions would overwrite master’s history. All I know for certain is that Richard wiped out master’s history 20 days after I had created master.

Now another interesting thing was revealed when I looked further into the code Richard put into master. He had replaced README.md using some completely unrelated project name. The project name isn’t related to anything we have at work. Since Richard works as an independent freelance developer, I conclude that he has taken the source code that he wrote for another client, that was saved in a branch named master and rewrote the history in our repo’s master branch with that other code. I’ll also mention that his repo was for a project he wanted to do for us, because it was for a software solution that although well written, wasn’t anything we needed. It really is the situation where this project is a solution in search of a problem. We already have a third-party product that does much of what Richard’s solution does, so although Richard’s app has some features not in the third-party app, it isn’t something we really needed.

At this point I’ve given you all the pertinent facts. I have limited independent freelance experience. I have never written something for one client, then tried to pass it off to another client as something they should use and pay me for. But, because of my limited experience, I don’t know if what Richard has done is common, acceptable practice amount freelance developers. Please, let me know, as doing freelance work is something I want to do more of. But I don’t want to do something that shouldn’t be done, if it is unethical, if not illegal.

An excellent compilation of what’s new in XAML and Windows 10

I’ve behind in listening to the Dot Net Rocks podcast. (Sorry Carl and Richard.) I was listening to one from May of this year. They mentioned a web page by Sahil Malek titled New in XAML VS2015 Windows 10. Sahil has made several tweets about what’s new in XAML in Windows 10. I’m very thankful that he’s tweeted on all of these cool, new things!!

Getting the list of groups the logged in user is a member of in Active Directory

I was recently tasked with coming up with a way of listing who the currently logged in user is, and also all of the groups he/she is a member of in the domain. So I wrote a console app that should the user and the domain groups they’re a member of in an Active Directory. This is a C# application.

First I’ll give the class definition I created to hold the data. This class is called UserGroupInfo:

using System.Collections.Generic;

namespace UserGroupsConsole
{
    public class UserGroupInfo
    {
        public string Username { get; set; }
        public List<string> UsersGroups { get; set; }
    }
}

Next is the RetrieveUserInfo class. This is the one that does all of the heavy lifting. Please note that I had to add a reference to the System.DirectoryServices.AccountManagement.dll in order to make this work:

using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;

namespace UserGroupsConsole
{
    public static class RetrieveUserInfo
    {
        public static UserGroupInfo GetUserInfo()
        {
            UserGroupInfo ugi = new UserGroupInfo();
            ugi.UsersGroups = new List<string>();

            //this is the easy part
            string user = WindowsIdentity.GetCurrent().Name;

            if (user.IndexOf('\\') >= 0)
            {
                ugi.Username = user.Split('\\')[1];
            }
            else
            {
                ugi.Username = user;
            }

            //now get the user's AD groups, makes use of System.Security.Principal
            IdentityReferenceCollection irc = WindowsIdentity.GetCurrent().Groups;

            foreach (var item in irc)
            {
                ugi.UsersGroups.Add(GetGroupNameBySid(item.Value));
            }


            return ugi;
        }

        /*
         * Needed to add a reference to System.DirectoryServices.AccountManagement in
         * order to be able to use PrincipalContext and GroupPrincipal.
         */
        public static string GetGroupNameBySid(string sid)
        {
            PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
            GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, sid);

            if (group == null)
            {
                return sid;
            }

            return group.SamAccountName;
        }
    }
}

And lastly of course is the main program that runs it:

using System;

namespace UserGroupsConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            UserGroupInfo ugi = RetrieveUserInfo.GetUserInfo();

            Console.WriteLine("User Name: {0}", ugi.Username);
            Console.WriteLine("AD Groups that {0} is a member of:", ugi.Username);
            for (int i = 0; i < ugi.UsersGroups.Count; i++)
            {
                Console.WriteLine("\t{0}", ugi.UsersGroups[i]);
            }

            Console.WriteLine("\r\n\r\nPress Enter to quit");
            Console.ReadLine();
        }
    }
}

Please note the user of PrincipalContext and GroupPrincipal classes (in System.DirectoryServices.AccountManagement namespace). I needed that in order to resolve the Security Identifier (SID) value, into a user friendly name.

I wrote this using Visual Studio 2013.